forked from OSchip/llvm-project
[flang] checkpoint with clang workaround
Original-commit: flang-compiler/f18@c4a2aaf8b1 Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false
This commit is contained in:
parent
ae308415bb
commit
e798ab7d91
|
@ -54,10 +54,10 @@ namespace Fortran::common {
|
|||
// Helper templates for combining a list of lambdas into an anonymous
|
||||
// struct for use with std::visit() on a std::variant<> sum type.
|
||||
// E.g.: std::visit(visitors{
|
||||
// [&](const UnaryExpr &x) { ... },
|
||||
// [&](const BinaryExpr &x) { ... },
|
||||
// [&](const firstType &x) { ... },
|
||||
// [&](const secondType &x) { ... },
|
||||
// ...
|
||||
// }, structure.unionMember);
|
||||
// [&](const auto &catchAll) { ... }}, variantObject);
|
||||
|
||||
template<typename... LAMBDAS> struct visitors : LAMBDAS... {
|
||||
using LAMBDAS::operator()...;
|
||||
|
|
|
@ -33,9 +33,11 @@ std::ostream &Operation<D, R, O...>::Dump(std::ostream &o) const {
|
|||
if constexpr (operands() > 1) {
|
||||
operand<1>().Dump(o << infix_);
|
||||
}
|
||||
return o << derived().postfix_;
|
||||
return o << derived().suffix_;
|
||||
}
|
||||
|
||||
// TODO: dump Convert<Integer,x> as INT(x,KIND=), &c.
|
||||
|
||||
template<typename D, typename R, typename... O>
|
||||
auto Operation<D, R, O...>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
|
@ -58,42 +60,32 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context,
|
|||
const Scalar<Operand> &c) -> std::optional<Scalar<Result>> {
|
||||
if constexpr (std::is_same_v<Result, Operand>) {
|
||||
return {c};
|
||||
}
|
||||
if constexpr (std::is_same_v<Result, SomeType>) {
|
||||
} else if constexpr (std::is_same_v<Result, SomeType>) {
|
||||
using Generic = SomeKind<Operand::category>;
|
||||
if constexpr (std::is_same_v<Operand, Generic>) {
|
||||
return {Scalar<Result>{c}};
|
||||
} else {
|
||||
return {Scalar<Result>{Generic{c}}};
|
||||
}
|
||||
}
|
||||
if constexpr (std::is_same_v<Operand, SomeType>) {
|
||||
} else if constexpr (std::is_same_v<Operand, SomeType>) {
|
||||
return std::visit(
|
||||
[&](const auto &x) -> std::optional<Scalar<Result>> {
|
||||
return Convert<Result, std::decay_t<decltype(x)>>::FoldScalar(
|
||||
context, x);
|
||||
using Ty = std::decay_t<decltype(x)>;
|
||||
return Convert<Result, Ty>::FoldScalar(context, x);
|
||||
},
|
||||
c.u);
|
||||
}
|
||||
// Result and Operand are distinct types with known categories.
|
||||
if constexpr (std::is_same_v<Result, SomeKind<Result::category>>) {
|
||||
} else if constexpr (std::is_same_v<Result, SomeKind<Result::category>>) {
|
||||
if constexpr (Result::category == Operand::category) {
|
||||
return {Scalar<Result>{c}};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
// Result is a specific type.
|
||||
if constexpr (std::is_same_v<Operand, SomeKind<Operand::category>>) {
|
||||
} else if constexpr (std::is_same_v<Operand, SomeKind<Operand::category>>) {
|
||||
return std::visit(
|
||||
[&](const auto &x) -> std::optional<Scalar<Result>> {
|
||||
return Convert<Result,
|
||||
ScalarValueType<std::decay_t<decltype(x)>>>::FoldScalar(context,
|
||||
x);
|
||||
using Ty = ScalarValueType<std::decay_t<decltype(x)>>;
|
||||
return Convert<Result, Ty>::FoldScalar(context, x);
|
||||
},
|
||||
c.u);
|
||||
}
|
||||
// Result and Operand are distinct specific types.
|
||||
if constexpr (Result::category == TypeCategory::Integer) {
|
||||
} else if constexpr (Result::category == TypeCategory::Integer) {
|
||||
if constexpr (Operand::category == TypeCategory::Integer) {
|
||||
auto converted{Scalar<Result>::ConvertSigned(c)};
|
||||
if (converted.overflow) {
|
||||
|
@ -101,8 +93,7 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context,
|
|||
} else {
|
||||
return {std::move(converted.value)};
|
||||
}
|
||||
}
|
||||
if constexpr (Operand::category == TypeCategory::Real) {
|
||||
} else if constexpr (Operand::category == TypeCategory::Real) {
|
||||
auto converted{c.template ToInteger<Scalar<Result>>()};
|
||||
if (converted.flags.test(RealFlag::InvalidArgument)) {
|
||||
context.messages.Say(
|
||||
|
@ -113,14 +104,12 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context,
|
|||
return {std::move(converted.value)};
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (Result::category == TypeCategory::Real) {
|
||||
} else if constexpr (Result::category == TypeCategory::Real) {
|
||||
if constexpr (Operand::category == TypeCategory::Integer) {
|
||||
auto converted{Scalar<Result>::FromInteger(c)};
|
||||
RealFlagWarnings(context, converted.flags, "INTEGER to REAL conversion");
|
||||
return {std::move(converted.value)};
|
||||
}
|
||||
if constexpr (Operand::category == TypeCategory::Real) {
|
||||
} else if constexpr (Operand::category == TypeCategory::Real) {
|
||||
auto converted{Scalar<Result>::Convert(c)};
|
||||
RealFlagWarnings(context, converted.flags, "REAL to REAL conversion");
|
||||
return {std::move(converted.value)};
|
||||
|
@ -129,18 +118,35 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context,
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Dumping
|
||||
template<typename... A>
|
||||
std::ostream &DumpExprWithType(std::ostream &o, const std::variant<A...> &u) {
|
||||
std::visit(
|
||||
[&](const auto &x) {
|
||||
using Ty = typename std::remove_reference_t<decltype(x)>::Result;
|
||||
x.Dump(o << '(' << Ty::Dump() << "::") << ')';
|
||||
},
|
||||
u);
|
||||
return o;
|
||||
template<typename A>
|
||||
auto Negate<A>::FoldScalar(FoldingContext &context, const Scalar<Operand> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if constexpr (Result::category == TypeCategory::Integer) {
|
||||
auto negated{c.Negate()};
|
||||
if (negated.overflow) {
|
||||
context.messages.Say("INTEGER negation overflowed"_en_US);
|
||||
} else {
|
||||
return {std::move(negated.value)};
|
||||
}
|
||||
} else {
|
||||
return {c.Negate()}; // REAL & COMPLEX: no exceptions possible
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<int KIND, bool R>
|
||||
auto ComplexComponent<KIND, R>::FoldScalar(FoldingContext &context,
|
||||
const Scalar<Operand> &z) -> std::optional<Scalar<Result>> {
|
||||
return {isRealPart ? z.REAL() : z.AIMAG()};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Not<KIND>::FoldScalar(FoldingContext &context, const Scalar<Operand> &x)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return {Scalar<Result>{!x.IsTrue()}};
|
||||
}
|
||||
|
||||
// Dumping
|
||||
template<typename... A>
|
||||
std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) {
|
||||
std::visit(common::visitors{[&](const BOZLiteralConstant &x) {
|
||||
|
@ -165,12 +171,6 @@ std::ostream &Expr<SomeType>::Dump(std::ostream &o) const {
|
|||
return DumpExpr(o, u);
|
||||
}
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A>
|
||||
std::ostream &Unary<CRTP, RESULT, A>::Dump(
|
||||
std::ostream &o, const char *opr) const {
|
||||
return operand().Dump(o << opr) << ')';
|
||||
}
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A, typename B>
|
||||
std::ostream &Binary<CRTP, RESULT, A, B>::Dump(
|
||||
std::ostream &o, const char *opr, const char *before) const {
|
||||
|
@ -184,8 +184,6 @@ std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump(
|
|||
common::visitors{[&](const Scalar<Result> &n) { o << n.SignedDecimal(); },
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Parentheses<Result> &p) { p.Dump(o); },
|
||||
[&](const Negate &n) { n.Dump(o, "(-"); },
|
||||
[&](const Add &a) { a.Dump(o, "+"); },
|
||||
[&](const Subtract &s) { s.Dump(o, "-"); },
|
||||
[&](const Multiply &m) { m.Dump(o, "*"); },
|
||||
|
@ -193,9 +191,7 @@ std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump(
|
|||
[&](const Power &p) { p.Dump(o, "**"); },
|
||||
[&](const Max &m) { m.Dump(o, ",", "MAX("); },
|
||||
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
|
||||
[&](const auto &convert) {
|
||||
DumpExprWithType(o, convert.operand().u);
|
||||
}},
|
||||
[&](const auto &x) { x.Dump(o); }},
|
||||
u_);
|
||||
return o;
|
||||
}
|
||||
|
@ -209,8 +205,12 @@ std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump(
|
|||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Convert<Result, SomeInteger> &c) { c.Dump(o); },
|
||||
[&](const Convert<Result, SomeReal> &c) { c.Dump(o); },
|
||||
[&](const ComplexComponent<KIND, true> &z) { z.Dump(o); },
|
||||
[&](const ComplexComponent<KIND, false> &z) { z.Dump(o); },
|
||||
[&](const Parentheses<Result> &p) { p.Dump(o); },
|
||||
[&](const Negate &n) { n.Dump(o, "(-"); },
|
||||
[&](const Negate<Result> &n) { n.Dump(o); },
|
||||
[&](const Add &a) { a.Dump(o, "+"); },
|
||||
[&](const Subtract &s) { s.Dump(o, "-"); },
|
||||
[&](const Multiply &m) { m.Dump(o, "*"); },
|
||||
|
@ -218,12 +218,7 @@ std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump(
|
|||
[&](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 RealPart &z) { z.Dump(o, "REAL("); },
|
||||
[&](const AIMAG &p) { p.Dump(o, "AIMAG("); },
|
||||
[&](const auto &convert) {
|
||||
DumpExprWithType(o, convert.operand().u);
|
||||
}},
|
||||
[&](const Min &m) { m.Dump(o, ",", "MIN("); }},
|
||||
u_);
|
||||
return o;
|
||||
}
|
||||
|
@ -236,15 +231,14 @@ std::ostream &Expr<Type<TypeCategory::Complex, KIND>>::Dump(
|
|||
},
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Parentheses<Result> &p) { p.Dump(o); },
|
||||
[&](const Negate &n) { n.Dump(o, "(-"); },
|
||||
[&](const Add &a) { a.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 CMPLX &c) { c.Dump(o, ","); },
|
||||
[&](const auto &x) { x.Dump(o); }},
|
||||
u_);
|
||||
return o;
|
||||
}
|
||||
|
@ -280,7 +274,7 @@ std::ostream &Expr<Type<TypeCategory::Logical, KIND>>::Dump(
|
|||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
// [&](const Parentheses<Result> &p) { p.Dump(o); },
|
||||
[&](const Not &n) { n.Dump(o, "(.NOT."); },
|
||||
[&](const Not<KIND> &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."); },
|
||||
|
@ -328,15 +322,6 @@ int Binary<CRTP, RESULT, A, B>::Rank() const {
|
|||
}
|
||||
|
||||
// Folding
|
||||
template<typename CRTP, typename RESULT, typename A>
|
||||
auto Unary<CRTP, RESULT, A>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if (std::optional<Scalar<Operand>> c{operand_->Fold(context)}) {
|
||||
return static_cast<CRTP *>(this)->FoldScalar(context, *c);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A, typename B>
|
||||
auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
|
@ -348,55 +333,6 @@ auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Integer, KIND>>::ConvertInteger::FoldScalar(
|
||||
FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
auto converted{Scalar<Result>::ConvertSigned(x)};
|
||||
if (converted.overflow) {
|
||||
context.messages.Say("integer conversion overflowed"_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(converted.value)};
|
||||
},
|
||||
c.u);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Integer, KIND>>::ConvertReal::FoldScalar(
|
||||
FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
auto converted{x.template ToInteger<Scalar<Result>>()};
|
||||
if (converted.flags.test(RealFlag::Overflow)) {
|
||||
context.messages.Say("real->integer conversion overflowed"_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (converted.flags.test(RealFlag::InvalidArgument)) {
|
||||
context.messages.Say(
|
||||
"real->integer conversion: invalid argument"_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(converted.value)};
|
||||
},
|
||||
c.u);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Integer, KIND>>::Negate::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
auto negated{c.Negate()};
|
||||
if (negated.overflow) {
|
||||
context.messages.Say("integer negation overflowed"_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(negated.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Integer, KIND>>::Add::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
|
@ -492,12 +428,12 @@ auto Expr<Type<TypeCategory::Integer, KIND>>::Min::FoldScalar(
|
|||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if (auto c{ScalarValue()}) {
|
||||
return c;
|
||||
}
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
using Ty = std::decay_t<decltype(x)>;
|
||||
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
|
||||
return {x};
|
||||
}
|
||||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
if (auto c{x.Fold(context)}) {
|
||||
if constexpr (std::is_same_v<Ty, Parentheses<Result>>) {
|
||||
|
@ -514,39 +450,6 @@ auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context)
|
|||
u_);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::ConvertInteger::FoldScalar(
|
||||
FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
auto converted{Scalar<Result>::FromInteger(x)};
|
||||
RealFlagWarnings(context, converted.flags, "integer->real conversion");
|
||||
return {std::move(converted.value)};
|
||||
},
|
||||
c.u);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::ConvertReal::FoldScalar(
|
||||
FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
auto converted{Scalar<Result>::Convert(x)};
|
||||
RealFlagWarnings(context, converted.flags, "real conversion");
|
||||
return {std::move(converted.value)};
|
||||
},
|
||||
c.u);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::Negate::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return {c.Negate()};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::Add::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
|
@ -624,37 +527,26 @@ auto Expr<Type<TypeCategory::Real, KIND>>::Min::FoldScalar(
|
|||
return {a};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::RealPart::FoldScalar(
|
||||
FoldingContext &context,
|
||||
const Scalar<SameKind<TypeCategory::Complex, Result>> &z)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return {z.REAL()};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::AIMAG::FoldScalar(
|
||||
FoldingContext &context,
|
||||
const Scalar<SameKind<TypeCategory::Complex, Result>> &z)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return {z.AIMAG()};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if (auto c{ScalarValue()}) {
|
||||
return c;
|
||||
}
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
using Ty = std::decay_t<decltype(x)>;
|
||||
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
|
||||
return {x};
|
||||
}
|
||||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
if (auto c{x.Fold(context)}) {
|
||||
if (context.flushDenormalsToZero) {
|
||||
*c = c->FlushDenormalToZero();
|
||||
}
|
||||
u_ = *c;
|
||||
if constexpr (std::is_same_v<Ty, Parentheses<Result>>) {
|
||||
// Preserve parentheses around constants.
|
||||
u_ = Parentheses<Result>{Expr{*c}};
|
||||
} else {
|
||||
u_ = *c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
@ -663,13 +555,6 @@ auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context)
|
|||
u_);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Complex, KIND>>::Negate::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &c)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return {c.Negate()};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Complex, KIND>>::Add::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
|
@ -739,18 +624,23 @@ auto Expr<Type<TypeCategory::Complex, KIND>>::CMPLX::FoldScalar(
|
|||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Complex, KIND>>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if (auto c{ScalarValue()}) {
|
||||
return c;
|
||||
}
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
using Ty = std::decay_t<decltype(x)>;
|
||||
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
|
||||
return {x};
|
||||
}
|
||||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
if (auto c{x.Fold(context)}) {
|
||||
if (context.flushDenormalsToZero) {
|
||||
*c = c->FlushDenormalToZero();
|
||||
}
|
||||
u_ = *c;
|
||||
if constexpr (std::is_same_v<Ty, Parentheses<Result>>) {
|
||||
// Preserve parentheses around constants.
|
||||
u_ = Parentheses<Result>{Expr{*c}};
|
||||
} else {
|
||||
u_ = *c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
@ -792,12 +682,12 @@ auto Expr<Type<TypeCategory::Character, KIND>>::Min::FoldScalar(
|
|||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Character, KIND>>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if (auto c{ScalarValue()}) {
|
||||
return c;
|
||||
}
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
using Ty = std::decay_t<decltype(x)>;
|
||||
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
|
||||
return {x};
|
||||
}
|
||||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
if (auto c{x.Fold(context)}) {
|
||||
u_ = *c;
|
||||
|
@ -860,13 +750,6 @@ auto Comparison<A>::FoldScalar(FoldingContext &c, const Scalar<Operand> &a,
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Logical, KIND>>::Not::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &x)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
return {Scalar<Result>{!x.IsTrue()}};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Logical, KIND>>::And::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
|
@ -898,12 +781,12 @@ auto Expr<Type<TypeCategory::Logical, KIND>>::Neqv::FoldScalar(
|
|||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Logical, KIND>>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if (auto c{ScalarValue()}) {
|
||||
return c;
|
||||
}
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar<Result>> {
|
||||
using Ty = std::decay_t<decltype(x)>;
|
||||
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
|
||||
return {x};
|
||||
}
|
||||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
if (auto c{x.Fold(context)}) {
|
||||
u_ = *c;
|
||||
|
@ -989,13 +872,6 @@ int Expr<SomeType>::Rank() const {
|
|||
u);
|
||||
}
|
||||
|
||||
template class Expr<SomeType>;
|
||||
template class Expr<SomeKind<TypeCategory::Integer>>;
|
||||
template class Expr<SomeKind<TypeCategory::Real>>;
|
||||
template class Expr<SomeKind<TypeCategory::Complex>>;
|
||||
template class Expr<SomeKind<TypeCategory::Character>>;
|
||||
template class Expr<SomeKind<TypeCategory::Logical>>;
|
||||
|
||||
template class Expr<Type<TypeCategory::Integer, 1>>;
|
||||
template class Expr<Type<TypeCategory::Integer, 2>>;
|
||||
template class Expr<Type<TypeCategory::Integer, 4>>;
|
||||
|
@ -1011,11 +887,7 @@ template class Expr<Type<TypeCategory::Complex, 4>>;
|
|||
template class Expr<Type<TypeCategory::Complex, 8>>;
|
||||
template class Expr<Type<TypeCategory::Complex, 10>>;
|
||||
template class Expr<Type<TypeCategory::Complex, 16>>;
|
||||
template class Expr<Type<TypeCategory::Character, 1>>;
|
||||
template class Expr<Type<TypeCategory::Logical, 1>>;
|
||||
template class Expr<Type<TypeCategory::Logical, 2>>;
|
||||
template class Expr<Type<TypeCategory::Logical, 4>>;
|
||||
template class Expr<Type<TypeCategory::Logical, 8>>;
|
||||
template class Expr<Type<TypeCategory::Character, 1>>; // TODO others
|
||||
|
||||
template struct Comparison<Type<TypeCategory::Integer, 1>>;
|
||||
template struct Comparison<Type<TypeCategory::Integer, 2>>;
|
||||
|
@ -1032,5 +904,18 @@ template struct Comparison<Type<TypeCategory::Complex, 4>>;
|
|||
template struct Comparison<Type<TypeCategory::Complex, 8>>;
|
||||
template struct Comparison<Type<TypeCategory::Complex, 10>>;
|
||||
template struct Comparison<Type<TypeCategory::Complex, 16>>;
|
||||
template struct Comparison<Type<TypeCategory::Character, 1>>;
|
||||
template struct Comparison<Type<TypeCategory::Character, 1>>; // TODO others
|
||||
|
||||
template class Expr<Type<TypeCategory::Logical, 1>>;
|
||||
template class Expr<Type<TypeCategory::Logical, 2>>;
|
||||
template class Expr<Type<TypeCategory::Logical, 4>>;
|
||||
template class Expr<Type<TypeCategory::Logical, 8>>;
|
||||
|
||||
template class Expr<SomeInteger>;
|
||||
template class Expr<SomeReal>;
|
||||
template class Expr<SomeComplex>;
|
||||
template class Expr<SomeCharacter>;
|
||||
template class Expr<SomeLogical>;
|
||||
|
||||
template class Expr<SomeType>;
|
||||
} // namespace Fortran::evaluate
|
||||
|
|
|
@ -46,7 +46,19 @@ public:
|
|||
template<int J> using Operand = std::tuple_element_t<J, OperandTypes>;
|
||||
using FoldableTrait = std::true_type;
|
||||
|
||||
static_assert(Result::kind > 0); // Operations have specific Result types
|
||||
|
||||
#if !__clang__
|
||||
CLASS_BOILERPLATE(Operation)
|
||||
#else // clang 6.0 erroneously deletes the "=default" copy constructor
|
||||
Operation() = delete;
|
||||
Operation(const Operation &that) : operand_{that.operand_} {}
|
||||
Operation(Operation &&) = default;
|
||||
Operation &operator=(const Operation &) = default;
|
||||
Operation &operator=(Operation &&) = default;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
#endif
|
||||
|
||||
Operation(Expr<OPERAND> &&... x) : operand_{std::move(x)...} {}
|
||||
Operation(const Expr<OPERAND> &... x) : operand_{x...} {}
|
||||
|
||||
|
@ -63,16 +75,25 @@ public:
|
|||
|
||||
protected:
|
||||
// Overridable strings for Dump()
|
||||
static constexpr const char *prefix_{"("}, *infix_{""}, *postfix_{")"};
|
||||
static constexpr const char *prefix_{"("}, *infix_{""}, *suffix_{")"};
|
||||
|
||||
private:
|
||||
std::tuple<CopyableIndirection<Expr<OPERAND>>...> operand_;
|
||||
};
|
||||
|
||||
template<typename TO, typename FROM>
|
||||
struct Convert : public Operation<Convert<TO, FROM>, TO, FROM> {
|
||||
using Base = Operation<Convert<TO, FROM>, TO, FROM>;
|
||||
using Base::Base;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &);
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
class Parentheses : public Operation<Parentheses<A>, A, A> {
|
||||
struct Parentheses : public Operation<Parentheses<A>, A, A> {
|
||||
using Base = Operation<Parentheses, A, A>;
|
||||
friend Base;
|
||||
using Base::Base;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
|
@ -82,34 +103,44 @@ class Parentheses : public Operation<Parentheses<A>, A, A> {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename TO, typename FROM>
|
||||
class Convert : public Operation<Convert<TO, FROM>, TO, FROM> {
|
||||
using Base = Operation<Convert<TO, FROM>, TO, FROM>;
|
||||
friend Base;
|
||||
template<typename A> struct Negate : public Operation<Negate<A>, A, A> {
|
||||
using Base = Operation<Negate, A, A>;
|
||||
using Base::Base;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &);
|
||||
static constexpr const char *prefix_{"(-"};
|
||||
};
|
||||
|
||||
// Helper base classes for packaging subexpressions.
|
||||
template<typename CRTP, typename RESULT, typename A = RESULT> class Unary {
|
||||
public:
|
||||
using Result = RESULT;
|
||||
using Operand = A;
|
||||
using FoldableTrait = std::true_type;
|
||||
CLASS_BOILERPLATE(Unary)
|
||||
Unary(const Expr<Operand> &a) : operand_{a} {}
|
||||
Unary(Expr<Operand> &&a) : operand_{std::move(a)} {}
|
||||
Unary(CopyableIndirection<Expr<Operand>> &&a) : operand_{std::move(a)} {}
|
||||
const Expr<Operand> &operand() const { return *operand_; }
|
||||
Expr<Operand> &operand() { return *operand_; }
|
||||
std::ostream &Dump(std::ostream &, const char *opr) const;
|
||||
int Rank() const { return operand_.Rank(); }
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &); // TODO: array result
|
||||
private:
|
||||
CopyableIndirection<Expr<Operand>> operand_;
|
||||
// TODO: re vs. im can be dynamic
|
||||
template<int KIND, bool realPart = true>
|
||||
struct ComplexComponent
|
||||
: public Operation<ComplexComponent<KIND, realPart>,
|
||||
Type<TypeCategory::Real, KIND>, Type<TypeCategory::Complex, KIND>> {
|
||||
using Base = Operation<ComplexComponent, Type<TypeCategory::Real, KIND>,
|
||||
Type<TypeCategory::Complex, KIND>>;
|
||||
static constexpr bool isRealPart{realPart};
|
||||
using Base::Base;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &);
|
||||
static constexpr const char *prefix_{"(("};
|
||||
static constexpr const char *suffix_{isRealPart ? ")%RE)" : ")%IM)"};
|
||||
};
|
||||
|
||||
template<int KIND>
|
||||
struct Not : public Operation<Not<KIND>, Type<TypeCategory::Logical, KIND>,
|
||||
Type<TypeCategory::Logical, KIND>> {
|
||||
using Base = Operation<Not, Type<TypeCategory::Logical, KIND>,
|
||||
Type<TypeCategory::Logical, KIND>>;
|
||||
using Base::Base;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &);
|
||||
static constexpr const char *prefix_{"(.NOT."};
|
||||
};
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A = RESULT, typename B = A>
|
||||
|
@ -147,25 +178,7 @@ public:
|
|||
using Result = Type<TypeCategory::Integer, KIND>;
|
||||
using FoldableTrait = std::true_type;
|
||||
|
||||
struct ConvertInteger : public Unary<ConvertInteger, Result, SomeInteger> {
|
||||
using Unary<ConvertInteger, Result, SomeInteger>::Unary;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &);
|
||||
};
|
||||
|
||||
struct ConvertReal : public Unary<ConvertReal, Result, SomeReal> {
|
||||
using Unary<ConvertReal, Result, SomeReal>::Unary;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const SomeKindScalar<TypeCategory::Real> &);
|
||||
};
|
||||
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result>;
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Negate : public Un<Negate> {
|
||||
using Un<Negate>::Un;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &);
|
||||
};
|
||||
struct Add : public Bin<Add> {
|
||||
using Bin<Add>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
|
@ -208,31 +221,30 @@ public:
|
|||
Expr(std::int64_t n) : u_{Scalar<Result>{n}} {}
|
||||
Expr(std::uint64_t n) : u_{Scalar<Result>{n}} {}
|
||||
Expr(int n) : u_{Scalar<Result>{n}} {}
|
||||
Expr(const Expr<SomeInteger> &x) : u_{ConvertInteger{x}} {}
|
||||
Expr(Expr<SomeInteger> &&x) : u_{ConvertInteger{std::move(x)}} {}
|
||||
Expr(const Expr<SomeInteger> &x) : u_{Convert<Result, SomeInteger>{x}} {}
|
||||
Expr(Expr<SomeInteger> &&x)
|
||||
: u_{Convert<Result, SomeInteger>{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const Expr<Type<TypeCategory::Integer, K>> &x)
|
||||
: u_{ConvertInteger{Expr<SomeInteger>{x}}} {}
|
||||
: u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{x}}} {}
|
||||
template<int K>
|
||||
Expr(Expr<Type<TypeCategory::Integer, K>> &&x)
|
||||
: u_{ConvertInteger{Expr<SomeInteger>{std::move(x)}}} {}
|
||||
Expr(const Expr<SomeReal> &x) : u_{ConvertReal{x}} {}
|
||||
Expr(Expr<SomeReal> &&x) : u_{ConvertReal{std::move(x)}} {}
|
||||
: u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{std::move(x)}}} {}
|
||||
Expr(const Expr<SomeReal> &x) : u_{Convert<Result, SomeReal>{x}} {}
|
||||
Expr(Expr<SomeReal> &&x) : u_{Convert<Result, SomeReal>{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const Expr<Type<TypeCategory::Real, K>> &x)
|
||||
: u_{ConvertReal{Expr<SomeReal>{x}}} {}
|
||||
: u_{Convert<Result, SomeReal>{Expr<SomeReal>{x}}} {}
|
||||
template<int K>
|
||||
Expr(Expr<Type<TypeCategory::Real, K>> &&x)
|
||||
: u_{ConvertReal{Expr<SomeReal>{std::move(x)}}} {}
|
||||
: u_{Convert<Result, SomeReal>{Expr<SomeReal>{std::move(x)}}} {}
|
||||
template<typename A> Expr(const A &x) : u_{x} {}
|
||||
template<typename A>
|
||||
Expr(std::enable_if_t<!std::is_reference_v<A> &&
|
||||
(std::is_base_of_v<Un, A> || std::is_base_of_v<Bin, A>),
|
||||
A> &&x)
|
||||
: u_(std::move(x)) {}
|
||||
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_(std::move(x)) {}
|
||||
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
|
||||
|
||||
std::optional<Scalar<Result>> ScalarValue() const {
|
||||
// TODO: Also succeed when parenthesized constant
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
|
@ -240,9 +252,9 @@ public:
|
|||
|
||||
private:
|
||||
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<FunctionRef>, ConvertInteger, ConvertReal,
|
||||
Parentheses<Result>, Negate, Add, Subtract, Multiply, Divide, Power, Max,
|
||||
Min>
|
||||
CopyableIndirection<FunctionRef>, Convert<Result, SomeInteger>,
|
||||
Convert<Result, SomeReal>, Parentheses<Result>, Negate<Result>, Add,
|
||||
Subtract, Multiply, Divide, Power, Max, Min>
|
||||
u_;
|
||||
};
|
||||
|
||||
|
@ -254,23 +266,8 @@ public:
|
|||
// N.B. Real->Complex and Complex->Real conversions are done with CMPLX
|
||||
// and part access operations (resp.). Conversions between kinds of
|
||||
// Complex are done via decomposition to Real and reconstruction.
|
||||
struct ConvertInteger : public Unary<ConvertInteger, Result, SomeInteger> {
|
||||
using Unary<ConvertInteger, Result, SomeInteger>::Unary;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &);
|
||||
};
|
||||
struct ConvertReal : public Unary<ConvertReal, Result, SomeReal> {
|
||||
using Unary<ConvertReal, Result, SomeReal>::Unary;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const SomeKindScalar<TypeCategory::Real> &);
|
||||
};
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result>;
|
||||
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Negate : public Un<Negate> {
|
||||
using Un<Negate>::Un;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &);
|
||||
};
|
||||
struct Add : public Bin<Add> {
|
||||
using Bin<Add>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
|
@ -311,44 +308,33 @@ public:
|
|||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
|
||||
};
|
||||
template<typename CRTP>
|
||||
using ComplexUn =
|
||||
Unary<CRTP, Result, SameKind<TypeCategory::Complex, Result>>;
|
||||
struct RealPart : public ComplexUn<RealPart> {
|
||||
using ComplexUn<RealPart>::ComplexUn;
|
||||
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
|
||||
const Scalar<SameKind<TypeCategory::Complex, Result>> &);
|
||||
};
|
||||
struct AIMAG : public ComplexUn<AIMAG> {
|
||||
using ComplexUn<AIMAG>::ComplexUn;
|
||||
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
|
||||
const Scalar<SameKind<TypeCategory::Complex, Result>> &);
|
||||
};
|
||||
|
||||
CLASS_BOILERPLATE(Expr)
|
||||
Expr(const Scalar<Result> &x) : u_{x} {}
|
||||
Expr(const Expr<SomeInteger> &x) : u_{ConvertInteger{x}} {}
|
||||
Expr(Expr<SomeInteger> &&x) : u_{ConvertInteger{std::move(x)}} {}
|
||||
Expr(const Expr<SomeInteger> &x) : u_{Convert<Result, SomeInteger>{x}} {}
|
||||
Expr(Expr<SomeInteger> &&x)
|
||||
: u_{Convert<Result, SomeInteger>{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const Expr<Type<TypeCategory::Integer, K>> &x)
|
||||
: u_{ConvertInteger{Expr<SomeInteger>{x}}} {}
|
||||
: u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{x}}} {}
|
||||
template<int K>
|
||||
Expr(Expr<Type<TypeCategory::Integer, K>> &&x)
|
||||
: u_{ConvertInteger{Expr<SomeInteger>{std::move(x)}}} {}
|
||||
Expr(const Expr<SomeReal> &x) : u_{ConvertReal{x}} {}
|
||||
Expr(Expr<SomeReal> &&x) : u_{ConvertReal{std::move(x)}} {}
|
||||
: u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{std::move(x)}}} {}
|
||||
Expr(const Expr<SomeReal> &x) : u_{Convert<Result, SomeReal>{x}} {}
|
||||
Expr(Expr<SomeReal> &&x) : u_{Convert<Result, SomeReal>{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const Expr<Type<TypeCategory::Real, K>> &x)
|
||||
: u_{ConvertReal{Expr<SomeReal>{x}}} {}
|
||||
: u_{Convert<Result, SomeReal>{Expr<SomeReal>{x}}} {}
|
||||
template<int K>
|
||||
Expr(Expr<Type<TypeCategory::Real, K>> &&x)
|
||||
: u_{ConvertReal{Expr<SomeReal>{std::move(x)}}} {}
|
||||
: u_{Convert<Result, SomeReal>{Expr<SomeReal>{std::move(x)}}} {}
|
||||
template<typename A> Expr(const A &x) : u_{x} {}
|
||||
template<typename A>
|
||||
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
|
||||
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
|
||||
|
||||
std::optional<Scalar<Result>> ScalarValue() const {
|
||||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
|
@ -357,8 +343,10 @@ public:
|
|||
private:
|
||||
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>,
|
||||
ConvertInteger, ConvertReal, Parentheses<Result>, Negate, Add, Subtract,
|
||||
Multiply, Divide, Power, IntPower, Max, Min, RealPart, AIMAG>
|
||||
Convert<Result, SomeInteger>, Convert<Result, SomeReal>,
|
||||
ComplexComponent<KIND, true>, ComplexComponent<KIND, false>,
|
||||
Parentheses<Result>, Negate<Result>, Add, Subtract, Multiply, Divide,
|
||||
Power, IntPower, Max, Min>
|
||||
u_;
|
||||
};
|
||||
|
||||
|
@ -367,13 +355,7 @@ public:
|
|||
using Result = Type<TypeCategory::Complex, KIND>;
|
||||
using FoldableTrait = std::true_type;
|
||||
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result>;
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Negate : public Un<Negate> {
|
||||
using Un<Negate>::Un;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &);
|
||||
};
|
||||
struct Add : public Bin<Add> {
|
||||
using Bin<Add>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
|
@ -420,6 +402,7 @@ public:
|
|||
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
|
||||
|
||||
std::optional<Scalar<Result>> ScalarValue() const {
|
||||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
|
@ -427,11 +410,27 @@ public:
|
|||
|
||||
private:
|
||||
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate, Add,
|
||||
Subtract, Multiply, Divide, Power, IntPower, CMPLX>
|
||||
CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate<Result>,
|
||||
Add, Subtract, Multiply, Divide, Power, IntPower, CMPLX>
|
||||
u_;
|
||||
};
|
||||
|
||||
extern template class Expr<Type<TypeCategory::Integer, 1>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 8>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 16>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 8>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 10>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 16>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 8>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 10>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 16>>;
|
||||
|
||||
template<int KIND> class Expr<Type<TypeCategory::Character, KIND>> {
|
||||
public:
|
||||
using Result = Type<TypeCategory::Character, KIND>;
|
||||
|
@ -462,6 +461,7 @@ public:
|
|||
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
|
||||
|
||||
std::optional<Scalar<Result>> ScalarValue() const {
|
||||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
|
@ -482,9 +482,8 @@ private:
|
|||
ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
|
||||
|
||||
template<typename A>
|
||||
struct Comparison
|
||||
: public Binary<Comparison<A>, Type<TypeCategory::Logical, 1>, A> {
|
||||
using Result = Type<TypeCategory::Logical, 1>;
|
||||
struct Comparison : public Binary<Comparison<A>, LogicalResult, A> {
|
||||
using Result = LogicalResult;
|
||||
using Operand = A;
|
||||
using Base = Binary<Comparison, Result, Operand>;
|
||||
CLASS_BOILERPLATE(Comparison)
|
||||
|
@ -498,27 +497,10 @@ struct Comparison
|
|||
RelationalOperator opr;
|
||||
};
|
||||
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 1>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 2>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 4>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 8>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 16>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 2>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 4>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 8>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 10>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 16>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 2>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 4>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 8>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 10>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 16>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Character, 1>>;
|
||||
|
||||
// Dynamically polymorphic comparisons whose operands are expressions of
|
||||
// the same supported kind of a particular type category.
|
||||
template<TypeCategory CAT> struct CategoryComparison {
|
||||
using Result = Type<TypeCategory::Logical, 1>;
|
||||
using Result = LogicalResult;
|
||||
CLASS_BOILERPLATE(CategoryComparison)
|
||||
template<int KIND> using KindComparison = Comparison<Type<CAT, KIND>>;
|
||||
template<int KIND> CategoryComparison(const KindComparison<KIND> &x) : u{x} {}
|
||||
|
@ -526,18 +508,14 @@ template<TypeCategory CAT> struct CategoryComparison {
|
|||
CategoryComparison(KindComparison<KIND> &&x) : u{std::move(x)} {}
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
int Rank() const { return 1; } // TODO
|
||||
typename KindsVariant<CAT, KindComparison>::type u;
|
||||
|
||||
KindsVariant<CAT, KindComparison> u;
|
||||
};
|
||||
|
||||
template<int KIND> class Expr<Type<TypeCategory::Logical, KIND>> {
|
||||
public:
|
||||
using Result = Type<TypeCategory::Logical, KIND>;
|
||||
using FoldableTrait = std::true_type;
|
||||
struct Not : Unary<Not, Result> {
|
||||
using Unary<Not, Result>::Unary;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &);
|
||||
};
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct And : public Bin<And> {
|
||||
using Bin<And>::Bin;
|
||||
|
@ -574,6 +552,7 @@ public:
|
|||
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
|
||||
|
||||
std::optional<Scalar<Result>> ScalarValue() const {
|
||||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
|
@ -583,34 +562,13 @@ private:
|
|||
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<FunctionRef>,
|
||||
// Parentheses<Result>,
|
||||
Not, And, Or, Eqv, Neqv, CategoryComparison<TypeCategory::Integer>,
|
||||
Not<KIND>, And, Or, Eqv, Neqv, CategoryComparison<TypeCategory::Integer>,
|
||||
CategoryComparison<TypeCategory::Real>,
|
||||
CategoryComparison<TypeCategory::Complex>,
|
||||
CategoryComparison<TypeCategory::Character>>
|
||||
u_;
|
||||
};
|
||||
|
||||
extern template class Expr<Type<TypeCategory::Integer, 1>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 8>>;
|
||||
extern template class Expr<Type<TypeCategory::Integer, 16>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 8>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 10>>;
|
||||
extern template class Expr<Type<TypeCategory::Real, 16>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 8>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 10>>;
|
||||
extern template class Expr<Type<TypeCategory::Complex, 16>>;
|
||||
extern template class Expr<Type<TypeCategory::Character, 1>>;
|
||||
extern template class Expr<Type<TypeCategory::Logical, 1>>;
|
||||
extern template class Expr<Type<TypeCategory::Logical, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Logical, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Logical, 8>>;
|
||||
|
||||
// Dynamically polymorphic expressions that can hold any supported kind
|
||||
// of a specific intrinsic type category.
|
||||
template<TypeCategory CAT> class Expr<SomeKind<CAT>> {
|
||||
|
@ -618,20 +576,16 @@ public:
|
|||
using Result = SomeKind<CAT>;
|
||||
using FoldableTrait = std::true_type;
|
||||
CLASS_BOILERPLATE(Expr)
|
||||
|
||||
template<int KIND> using KindExpr = Expr<Type<CAT, KIND>>;
|
||||
template<int KIND> Expr(const KindExpr<KIND> &x) : u{x} {}
|
||||
template<int KIND> Expr(KindExpr<KIND> &&x) : u{std::move(x)} {}
|
||||
std::optional<Scalar<Result>> ScalarValue() const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &);
|
||||
int Rank() const;
|
||||
typename KindsVariant<CAT, KindExpr>::type u;
|
||||
};
|
||||
|
||||
extern template class Expr<SomeInteger>;
|
||||
extern template class Expr<SomeReal>;
|
||||
extern template class Expr<SomeComplex>;
|
||||
extern template class Expr<SomeCharacter>;
|
||||
extern template class Expr<SomeLogical>;
|
||||
KindsVariant<CAT, KindExpr> u;
|
||||
};
|
||||
|
||||
// BOZ literal constants need to be wide enough to hold an integer or real
|
||||
// value of any supported kind. They also need to be distinguishable from
|
||||
|
@ -666,7 +620,6 @@ public:
|
|||
u;
|
||||
};
|
||||
|
||||
extern template class Expr<SomeType>;
|
||||
using GenericExpr = Expr<SomeType>; // TODO: delete name?
|
||||
|
||||
template<typename A> using ResultType = typename std::decay_t<A>::Result;
|
||||
|
@ -675,7 +628,15 @@ template<typename A> using ResultType = typename std::decay_t<A>::Result;
|
|||
// These definitions are created with temporary helper macros to reduce
|
||||
// C++ boilerplate. All combinations of lvalue and rvalue references are
|
||||
// allowed for operands.
|
||||
template<typename A> A operator-(const A &x) { return {typename A::Negate{x}}; }
|
||||
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(FUNC, CONSTR) \
|
||||
template<typename A> A FUNC(const A &x, const A &y) { \
|
||||
|
@ -728,5 +689,35 @@ 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 struct Comparison<Type<TypeCategory::Integer, 1>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 2>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 4>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 8>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Integer, 16>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 2>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 4>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 8>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 10>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Real, 16>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 2>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 4>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 8>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 10>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Complex, 16>>;
|
||||
extern template struct Comparison<Type<TypeCategory::Character, 1>>; // TODO
|
||||
// more
|
||||
extern template class Expr<Type<TypeCategory::Logical, 1>>;
|
||||
extern template class Expr<Type<TypeCategory::Logical, 2>>;
|
||||
extern template class Expr<Type<TypeCategory::Logical, 4>>;
|
||||
extern template class Expr<Type<TypeCategory::Logical, 8>>;
|
||||
extern template class Expr<SomeInteger>;
|
||||
extern template class Expr<SomeReal>;
|
||||
extern template class Expr<SomeComplex>;
|
||||
extern template class Expr<SomeCharacter>;
|
||||
extern template class Expr<SomeLogical>;
|
||||
extern template class Expr<SomeType>;
|
||||
|
||||
} // namespace Fortran::evaluate
|
||||
#endif // FORTRAN_EVALUATE_EXPRESSION_H_
|
||||
|
|
|
@ -149,16 +149,20 @@ using LogicalResult = Type<TypeCategory::Logical, 1>;
|
|||
// These macros and template create instances of std::variant<> that can contain
|
||||
// applications of some class template to all of the supported kinds of
|
||||
// a category of intrinsic type.
|
||||
template<TypeCategory CAT, template<int> class T> struct KindsVariant;
|
||||
template<TypeCategory CAT, template<int> class T> struct VariantOverKinds;
|
||||
#define TKIND(K) T<K>
|
||||
#define MAKE(Cat, CAT) \
|
||||
template<template<int> class T> struct KindsVariant<TypeCategory::Cat, T> { \
|
||||
template<template<int> class T> \
|
||||
struct VariantOverKinds<TypeCategory::Cat, T> { \
|
||||
using type = std::variant<FOR_EACH_##CAT##_KIND(TKIND, COMMA)>; \
|
||||
};
|
||||
FOR_EACH_CATEGORY(MAKE)
|
||||
#undef MAKE
|
||||
#undef TKIND
|
||||
|
||||
template<TypeCategory CAT, template<int> class T>
|
||||
using KindsVariant = typename VariantOverKinds<CAT, T>::type;
|
||||
|
||||
// Map scalar value types back to their Fortran types.
|
||||
// For every type T = Type<CAT, KIND>, TypeOfScalarValue<T>> == T.
|
||||
// E.g., TypeOfScalarValue<Integer<32>> is Type<TypeCategory::Integer, 4>.
|
||||
|
@ -195,7 +199,6 @@ template<TypeCategory CAT> struct SomeKindScalar {
|
|||
static constexpr TypeCategory category{CAT};
|
||||
CLASS_BOILERPLATE(SomeKindScalar)
|
||||
|
||||
template<int KIND> using KindScalar = Scalar<Type<CAT, KIND>>;
|
||||
template<typename A> SomeKindScalar(const A &x) : u{x} {}
|
||||
template<typename A>
|
||||
SomeKindScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
|
@ -213,7 +216,8 @@ template<TypeCategory CAT> struct SomeKindScalar {
|
|||
return common::GetIf<std::string>(u);
|
||||
}
|
||||
|
||||
typename KindsVariant<CAT, KindScalar>::type u;
|
||||
template<int KIND> using KindScalar = Scalar<Type<CAT, KIND>>;
|
||||
KindsVariant<CAT, KindScalar> u;
|
||||
};
|
||||
|
||||
// Holds a scalar constant of any intrinsic category and size.
|
||||
|
|
|
@ -265,20 +265,16 @@ static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral(
|
|||
|
||||
static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral(
|
||||
ExpressionAnalyzer &ea, const parser::SignedRealLiteralConstant &x) {
|
||||
auto result{AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))};
|
||||
if (result.has_value()) {
|
||||
if (auto result{
|
||||
AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) {
|
||||
if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
|
||||
if (sign == parser::Sign::Negative) {
|
||||
std::visit(
|
||||
[](auto &rk) {
|
||||
using t = std::decay_t<decltype(rk)>;
|
||||
rk = typename t::Negate{rk};
|
||||
},
|
||||
result->u);
|
||||
return {-*result};
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
Loading…
Reference in New Issue