forked from OSchip/llvm-project
[flang] checkpoint
Original-commit: flang-compiler/f18@fc470dc851 Reviewed-on: https://github.com/flang-compiler/f18/pull/144 Tree-same-pre-rewrite: false
This commit is contained in:
parent
943b50289b
commit
35ad0036aa
|
@ -30,15 +30,15 @@ using DefaultIntegerExpr = IntegerExpr<DefaultInteger::kind>;
|
|||
template<int KIND> using RealExpr = Expr<Type<Category::Real, KIND>>;
|
||||
template<int KIND> using ComplexExpr = Expr<Type<Category::Complex, KIND>>;
|
||||
template<int KIND> using CharacterExpr = Expr<Type<Category::Character, KIND>>;
|
||||
using LogicalExpr = Expr<Type<Category::Logical, 1>>;
|
||||
template<int KIND> using LogicalExpr = Expr<Type<Category::Logical, KIND>>;
|
||||
|
||||
// An expression whose result is of a particular type category and
|
||||
// any supported kind.
|
||||
template<Category CAT> struct CategoryExpr;
|
||||
using GenericIntegerExpr = CategoryExpr<Category::Integer>;
|
||||
using GenericRealExpr = CategoryExpr<Category::Real>;
|
||||
using GenericComplexExpr = CategoryExpr<Category::Complex>;
|
||||
using GenericCharacterExpr = CategoryExpr<Category::Character>;
|
||||
// An expression whose result is within one particular type category and
|
||||
// of any supported kind.
|
||||
using AnyKindIntegerExpr = Expr<AnyKindType<Category::Integer>>;
|
||||
using AnyKindRealExpr = Expr<AnyKindType<Category::Real>>;
|
||||
using AnyKindComplexExpr = Expr<AnyKindType<Category::Complex>>;
|
||||
using AnyKindCharacterExpr = Expr<AnyKindType<Category::Character>>;
|
||||
using AnyKindLogicalExpr = Expr<AnyKindType<Category::Logical>>;
|
||||
|
||||
// A completely generic expression.
|
||||
struct GenericExpr;
|
||||
|
|
|
@ -43,7 +43,7 @@ std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) {
|
|||
}
|
||||
|
||||
template<Category CAT>
|
||||
std::ostream &CategoryExpr<CAT>::Dump(std::ostream &o) const {
|
||||
std::ostream &Expr<AnyKindType<CAT>>::Dump(std::ostream &o) const {
|
||||
return DumpExpr(o, u);
|
||||
}
|
||||
|
||||
|
@ -56,15 +56,14 @@ std::ostream &GenericExpr::Dump(std::ostream &o) const {
|
|||
return DumpExpr(o, u);
|
||||
}
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A, typename ASCALAR>
|
||||
std::ostream &Unary<CRTP, RESULT, A, ASCALAR>::Dump(
|
||||
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,
|
||||
typename ASCALAR, typename BSCALAR>
|
||||
std::ostream &Binary<CRTP, RESULT, A, B, ASCALAR, BSCALAR>::Dump(
|
||||
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 {
|
||||
return right().Dump(left().Dump(o << before) << opr) << ')';
|
||||
}
|
||||
|
@ -148,24 +147,25 @@ std::ostream &CharacterExpr<KIND>::Dump(std::ostream &o) const {
|
|||
}
|
||||
|
||||
template<typename A> std::ostream &Comparison<A>::Dump(std::ostream &o) const {
|
||||
using Ty = typename A::Result;
|
||||
o << '(' << Ty::Dump() << "::";
|
||||
this->left().Dump(o); // TODO: is this-> still needed? Also below.
|
||||
o << '(' << A::Dump() << "::";
|
||||
this->left().Dump(o);
|
||||
o << '.' << EnumToString(this->opr) << '.';
|
||||
return this->right().Dump(o) << ')';
|
||||
}
|
||||
|
||||
std::ostream &LogicalExpr::Dump(std::ostream &o) const {
|
||||
std::visit(
|
||||
common::visitors{[&](const bool &tf) { o << (tf ? ".T." : ".F."); },
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Not &n) { n.Dump(o, "(.NOT."); },
|
||||
[&](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); }},
|
||||
template<int KIND>
|
||||
std::ostream &LogicalExpr<KIND>::Dump(std::ostream &o) const {
|
||||
std::visit(common::visitors{[&](const Scalar &tf) {
|
||||
o << (tf.IsTrue() ? ".TRUE." : ".FALSE.");
|
||||
},
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Not &n) { n.Dump(o, "(.NOT."); },
|
||||
[&](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;
|
||||
}
|
||||
|
@ -193,9 +193,8 @@ template<int KIND> SubscriptIntegerExpr CharacterExpr<KIND>::LEN() const {
|
|||
}
|
||||
|
||||
// Rank
|
||||
template<typename CRTP, typename RESULT, typename A, typename B,
|
||||
typename ASCALAR, typename BSCALAR>
|
||||
int Binary<CRTP, RESULT, A, B, ASCALAR, BSCALAR>::Rank() const {
|
||||
template<typename CRTP, typename RESULT, typename A, typename B>
|
||||
int Binary<CRTP, RESULT, A, B>::Rank() const {
|
||||
int lrank{left_.Rank()};
|
||||
if (lrank > 0) {
|
||||
return lrank;
|
||||
|
@ -204,18 +203,17 @@ int Binary<CRTP, RESULT, A, B, ASCALAR, BSCALAR>::Rank() const {
|
|||
}
|
||||
|
||||
// Folding
|
||||
template<typename CRTP, typename RESULT, typename A, typename ASCALAR>
|
||||
auto Unary<CRTP, RESULT, A, ASCALAR>::Fold(FoldingContext &context)
|
||||
template<typename CRTP, typename RESULT, typename A>
|
||||
auto Unary<CRTP, RESULT, A>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar> {
|
||||
if (std::optional<OperandScalar> c{operand_->Fold(context)}) {
|
||||
if (std::optional<OperandScalarConstant> c{operand_->Fold(context)}) {
|
||||
return static_cast<CRTP *>(this)->FoldScalar(context, *c);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A, typename B,
|
||||
typename ASCALAR, typename BSCALAR>
|
||||
auto Binary<CRTP, RESULT, A, B, ASCALAR, BSCALAR>::Fold(FoldingContext &context)
|
||||
template<typename CRTP, typename RESULT, typename A, typename B>
|
||||
auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar> {
|
||||
std::optional<LeftScalar> lc{left_->Fold(context)};
|
||||
std::optional<RightScalar> rc{right_->Fold(context)};
|
||||
|
@ -227,7 +225,7 @@ auto Binary<CRTP, RESULT, A, B, ASCALAR, BSCALAR>::Fold(FoldingContext &context)
|
|||
|
||||
template<int KIND>
|
||||
auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
|
||||
const CategoryScalar<Category::Integer> &c) -> std::optional<Scalar> {
|
||||
const ScalarConstant<Category::Integer> &c) -> std::optional<Scalar> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar> {
|
||||
auto converted{Scalar::ConvertSigned(x)};
|
||||
|
@ -243,7 +241,7 @@ auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
|
|||
|
||||
template<int KIND>
|
||||
auto IntegerExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
|
||||
const CategoryScalar<Category::Real> &c) -> std::optional<Scalar> {
|
||||
const ScalarConstant<Category::Real> &c) -> std::optional<Scalar> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar> {
|
||||
auto converted{x.template ToInteger<Scalar>()};
|
||||
|
@ -401,8 +399,74 @@ auto CharacterExpr<KIND>::Fold(FoldingContext &context)
|
|||
return {}; // TODO
|
||||
}
|
||||
|
||||
std::optional<bool> LogicalExpr::Fold(FoldingContext &context) {
|
||||
return {}; // TODO and comparisons too
|
||||
template<typename A>
|
||||
auto Comparison<A>::FoldScalar(FoldingContext &c,
|
||||
const OperandScalarConstant &a, const OperandScalarConstant &b)
|
||||
-> std::optional<Scalar> {
|
||||
if constexpr (A::category == Category::Integer) {
|
||||
switch (a.CompareSigned(b)) {
|
||||
case Ordering::Less:
|
||||
return {opr == RelationalOperator::LE || opr == RelationalOperator::LE ||
|
||||
opr == RelationalOperator::NE};
|
||||
case Ordering::Equal:
|
||||
return {opr == RelationalOperator::LE || opr == RelationalOperator::EQ ||
|
||||
opr == RelationalOperator::GE};
|
||||
case Ordering::Greater:
|
||||
return {opr == RelationalOperator::NE || opr == RelationalOperator::GE ||
|
||||
opr == RelationalOperator::GT};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto LogicalExpr<KIND>::Not::FoldScalar(
|
||||
FoldingContext &context, const Scalar &x) -> std::optional<Scalar> {
|
||||
return {Scalar{!x.IsTrue()}};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto LogicalExpr<KIND>::And::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
return {Scalar{a.IsTrue() && b.IsTrue()}};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto LogicalExpr<KIND>::Or::FoldScalar(FoldingContext &context, const Scalar &a,
|
||||
const Scalar &b) -> std::optional<Scalar> {
|
||||
return {Scalar{a.IsTrue() || b.IsTrue()}};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto LogicalExpr<KIND>::Eqv::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
return {Scalar{a.IsTrue() == b.IsTrue()}};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto LogicalExpr<KIND>::Neqv::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
return {Scalar{a.IsTrue() != b.IsTrue()}};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto LogicalExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar> {
|
||||
using Ty = typename std::decay<decltype(x)>::type;
|
||||
if constexpr (std::is_same_v<Ty, Scalar>) {
|
||||
return {x};
|
||||
}
|
||||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
std::optional<Scalar> c{x.Fold(context)};
|
||||
if (c.has_value()) {
|
||||
u_ = *c;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
},
|
||||
u_);
|
||||
}
|
||||
|
||||
std::optional<GenericScalar> GenericExpr::ScalarValue() const {
|
||||
|
@ -417,25 +481,30 @@ std::optional<GenericScalar> GenericExpr::ScalarValue() const {
|
|||
}
|
||||
|
||||
template<Category CAT>
|
||||
auto CategoryExpr<CAT>::ScalarValue() const -> std::optional<Scalar> {
|
||||
auto Expr<AnyKindType<CAT>>::ScalarValue() const -> std::optional<Scalar> {
|
||||
return std::visit(
|
||||
[](const auto &x) -> std::optional<Scalar> {
|
||||
if (auto c{x.ScalarValue()}) {
|
||||
return {Scalar{std::move(*c)}};
|
||||
}
|
||||
return {};
|
||||
std::optional<Scalar> avoidBogusGCCWarning; // ... with return {};
|
||||
return avoidBogusGCCWarning;
|
||||
;
|
||||
},
|
||||
u);
|
||||
}
|
||||
|
||||
template<Category CAT>
|
||||
auto CategoryExpr<CAT>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
||||
auto Expr<AnyKindType<CAT>>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar> {
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar> {
|
||||
if (auto c{x.Fold(context)}) {
|
||||
return {Scalar{std::move(*c)}};
|
||||
}
|
||||
return {};
|
||||
std::optional<Scalar> avoidBogusGCCWarning; // ... with return {};
|
||||
return avoidBogusGCCWarning;
|
||||
;
|
||||
},
|
||||
u);
|
||||
}
|
||||
|
@ -451,10 +520,11 @@ std::optional<GenericScalar> GenericExpr::Fold(FoldingContext &context) {
|
|||
u);
|
||||
}
|
||||
|
||||
template struct CategoryExpr<Category::Integer>;
|
||||
template struct CategoryExpr<Category::Real>;
|
||||
template struct CategoryExpr<Category::Complex>;
|
||||
template struct CategoryExpr<Category::Character>;
|
||||
template class Expr<AnyKindType<Category::Integer>>;
|
||||
template class Expr<AnyKindType<Category::Real>>;
|
||||
template class Expr<AnyKindType<Category::Complex>>;
|
||||
template class Expr<AnyKindType<Category::Character>>;
|
||||
template class Expr<AnyKindType<Category::Logical>>;
|
||||
|
||||
template class Expr<Type<Category::Integer, 1>>;
|
||||
template class Expr<Type<Category::Integer, 2>>;
|
||||
|
@ -473,21 +543,24 @@ template class Expr<Type<Category::Complex, 10>>;
|
|||
template class Expr<Type<Category::Complex, 16>>;
|
||||
template class Expr<Type<Category::Character, 1>>;
|
||||
template class Expr<Type<Category::Logical, 1>>;
|
||||
template class Expr<Type<Category::Logical, 2>>;
|
||||
template class Expr<Type<Category::Logical, 4>>;
|
||||
template class Expr<Type<Category::Logical, 8>>;
|
||||
|
||||
template struct Comparison<IntegerExpr<1>>;
|
||||
template struct Comparison<IntegerExpr<2>>;
|
||||
template struct Comparison<IntegerExpr<4>>;
|
||||
template struct Comparison<IntegerExpr<8>>;
|
||||
template struct Comparison<IntegerExpr<16>>;
|
||||
template struct Comparison<RealExpr<2>>;
|
||||
template struct Comparison<RealExpr<4>>;
|
||||
template struct Comparison<RealExpr<8>>;
|
||||
template struct Comparison<RealExpr<10>>;
|
||||
template struct Comparison<RealExpr<16>>;
|
||||
template struct Comparison<ComplexExpr<2>>;
|
||||
template struct Comparison<ComplexExpr<4>>;
|
||||
template struct Comparison<ComplexExpr<8>>;
|
||||
template struct Comparison<ComplexExpr<10>>;
|
||||
template struct Comparison<ComplexExpr<16>>;
|
||||
template struct Comparison<CharacterExpr<1>>;
|
||||
template struct Comparison<Type<Category::Integer, 1>>;
|
||||
template struct Comparison<Type<Category::Integer, 2>>;
|
||||
template struct Comparison<Type<Category::Integer, 4>>;
|
||||
template struct Comparison<Type<Category::Integer, 8>>;
|
||||
template struct Comparison<Type<Category::Integer, 16>>;
|
||||
template struct Comparison<Type<Category::Real, 2>>;
|
||||
template struct Comparison<Type<Category::Real, 4>>;
|
||||
template struct Comparison<Type<Category::Real, 8>>;
|
||||
template struct Comparison<Type<Category::Real, 10>>;
|
||||
template struct Comparison<Type<Category::Real, 16>>;
|
||||
template struct Comparison<Type<Category::Complex, 2>>;
|
||||
template struct Comparison<Type<Category::Complex, 4>>;
|
||||
template struct Comparison<Type<Category::Complex, 8>>;
|
||||
template struct Comparison<Type<Category::Complex, 10>>;
|
||||
template struct Comparison<Type<Category::Complex, 16>>;
|
||||
template struct Comparison<Type<Category::Character, 1>>;
|
||||
} // namespace Fortran::evaluate
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
// context-independent hash table or sharing of common subexpressions.
|
||||
// Both deep copy and move semantics are supported for expression construction
|
||||
// and manipulation in place.
|
||||
// TODO: convenience wrappers for constructing conversions
|
||||
|
||||
#include "common.h"
|
||||
#include "expression-forward.h"
|
||||
|
@ -40,91 +39,59 @@ struct FoldingContext {
|
|||
parser::Messages *messages;
|
||||
};
|
||||
|
||||
// Holds a scalar constant of any kind in an intrinsic type category.
|
||||
template<Category CAT> struct CategoryScalar {
|
||||
CLASS_BOILERPLATE(CategoryScalar)
|
||||
template<int KIND> using KindScalar = typename Type<CAT, KIND>::Value;
|
||||
template<typename A> CategoryScalar(const A &x) : u{x} {}
|
||||
template<typename A>
|
||||
CategoryScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
: u{std::move(x)} {}
|
||||
typename KindsVariant<CAT, KindScalar>::type u;
|
||||
};
|
||||
|
||||
template<> struct CategoryScalar<Category::Logical> { std::variant<bool> u; };
|
||||
|
||||
// Holds a scalar constant of any intrinsic category and size.
|
||||
struct GenericScalar {
|
||||
CLASS_BOILERPLATE(GenericScalar)
|
||||
template<Category CAT, int KIND>
|
||||
GenericScalar(const typename Type<CAT, KIND>::Value &x)
|
||||
: u{CategoryScalar<CAT>{x}} {}
|
||||
template<Category CAT, int KIND>
|
||||
GenericScalar(typename Type<CAT, KIND>::Value &&x)
|
||||
: u{CategoryScalar<CAT>{std::move(x)}} {}
|
||||
template<typename A> GenericScalar(const A &x) : u{x} {}
|
||||
template<typename A>
|
||||
GenericScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
: u{std::move(x)} {}
|
||||
std::variant<CategoryScalar<Category::Integer>,
|
||||
CategoryScalar<Category::Real>, CategoryScalar<Category::Complex>,
|
||||
CategoryScalar<Category::Character>, bool>
|
||||
u;
|
||||
};
|
||||
|
||||
// Helper base classes for packaging subexpressions.
|
||||
template<typename CRTP, typename RESULT, typename A,
|
||||
typename ASCALAR = typename A::Scalar>
|
||||
class Unary {
|
||||
template<typename CRTP, typename RESULT, typename A = RESULT> class Unary {
|
||||
protected:
|
||||
using OperandType = A;
|
||||
using Operand = Expr<OperandType>;
|
||||
using OperandScalarConstant = typename OperandType::Value;
|
||||
|
||||
public:
|
||||
using Result = RESULT;
|
||||
using Scalar = typename Type<Result::category, Result::kind>::Value;
|
||||
using Scalar = typename Result::Value;
|
||||
using FoldableTrait = std::true_type;
|
||||
CLASS_BOILERPLATE(Unary)
|
||||
Unary(const A &a) : operand_{a} {}
|
||||
Unary(A &&a) : operand_{std::move(a)} {}
|
||||
Unary(CopyableIndirection<A> &&a) : operand_{std::move(a)} {}
|
||||
const A &operand() const { return *operand_; }
|
||||
A &operand() { return *operand_; }
|
||||
Unary(const Operand &a) : operand_{a} {}
|
||||
Unary(Operand &&a) : operand_{std::move(a)} {}
|
||||
Unary(CopyableIndirection<Operand> &&a) : operand_{std::move(a)} {}
|
||||
const Operand &operand() const { return *operand_; }
|
||||
Operand &operand() { return *operand_; }
|
||||
std::ostream &Dump(std::ostream &, const char *opr) const;
|
||||
int Rank() const { return operand_.Rank(); }
|
||||
std::optional<Scalar> Fold(FoldingContext &); // TODO: array result
|
||||
protected:
|
||||
using Operand = A;
|
||||
using OperandScalar = ASCALAR;
|
||||
|
||||
private:
|
||||
CopyableIndirection<Operand> operand_;
|
||||
};
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A, typename B = A,
|
||||
typename ASCALAR = typename A::Scalar,
|
||||
typename BSCALAR = typename B::Scalar>
|
||||
template<typename CRTP, typename RESULT, typename A = RESULT, typename B = A>
|
||||
class Binary {
|
||||
protected:
|
||||
using LeftType = A;
|
||||
using Left = Expr<LeftType>;
|
||||
using LeftScalar = typename LeftType::Value;
|
||||
using RightType = B;
|
||||
using Right = Expr<RightType>;
|
||||
using RightScalar = typename RightType::Value;
|
||||
|
||||
public:
|
||||
using Result = RESULT;
|
||||
using Scalar = typename Type<Result::category, Result::kind>::Value;
|
||||
using Scalar = typename Result::Value;
|
||||
using FoldableTrait = std::true_type;
|
||||
CLASS_BOILERPLATE(Binary)
|
||||
Binary(const A &a, const B &b) : left_{a}, right_{b} {}
|
||||
Binary(A &&a, B &&b) : left_{std::move(a)}, right_{std::move(b)} {}
|
||||
Binary(CopyableIndirection<const A> &&a, CopyableIndirection<const B> &&b)
|
||||
Binary(const Left &a, const Right &b) : left_{a}, right_{b} {}
|
||||
Binary(Left &&a, Right &&b) : left_{std::move(a)}, right_{std::move(b)} {}
|
||||
Binary(
|
||||
CopyableIndirection<const Left> &&a, CopyableIndirection<const Right> &&b)
|
||||
: left_{std::move(a)}, right_{std::move(b)} {}
|
||||
const A &left() const { return *left_; }
|
||||
A &left() { return *left_; }
|
||||
const B &right() const { return *right_; }
|
||||
B &right() { return *right_; }
|
||||
const Left &left() const { return *left_; }
|
||||
Left &left() { return *left_; }
|
||||
const Right &right() const { return *right_; }
|
||||
Right &right() { return *right_; }
|
||||
std::ostream &Dump(
|
||||
std::ostream &, const char *opr, const char *before = "(") const;
|
||||
int Rank() const;
|
||||
std::optional<Scalar> Fold(FoldingContext &);
|
||||
|
||||
protected:
|
||||
using Left = A;
|
||||
using Right = B;
|
||||
using LeftScalar = ASCALAR;
|
||||
using RightScalar = BSCALAR;
|
||||
|
||||
private:
|
||||
CopyableIndirection<Left> left_;
|
||||
CopyableIndirection<Right> right_;
|
||||
|
@ -139,25 +106,21 @@ public:
|
|||
using FoldableTrait = std::true_type;
|
||||
|
||||
struct ConvertInteger
|
||||
: public Unary<ConvertInteger, Result, GenericIntegerExpr,
|
||||
CategoryScalar<Category::Integer>> {
|
||||
using Unary<ConvertInteger, Result, GenericIntegerExpr,
|
||||
CategoryScalar<Category::Integer>>::Unary;
|
||||
: public Unary<ConvertInteger, Result, AnyKindType<Category::Integer>> {
|
||||
using Unary<ConvertInteger, Result, AnyKindType<Category::Integer>>::Unary;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const CategoryScalar<Category::Integer> &);
|
||||
FoldingContext &, const ScalarConstant<Category::Integer> &);
|
||||
};
|
||||
|
||||
struct ConvertReal : public Unary<ConvertReal, Result, GenericRealExpr,
|
||||
CategoryScalar<Category::Real>> {
|
||||
using Unary<ConvertReal, Result, GenericRealExpr,
|
||||
CategoryScalar<Category::Real>>::Unary;
|
||||
struct ConvertReal
|
||||
: public Unary<ConvertReal, Result, AnyKindType<Category::Real>> {
|
||||
using Unary<ConvertReal, Result, AnyKindType<Category::Real>>::Unary;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const CategoryScalar<Category::Real> &);
|
||||
FoldingContext &, const ScalarConstant<Category::Real> &);
|
||||
};
|
||||
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result, Expr>;
|
||||
template<typename CRTP>
|
||||
using Bin = Binary<CRTP, Result, Expr, Expr, Scalar, Scalar>;
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result>;
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Parentheses : public Un<Parentheses> {
|
||||
using Un<Parentheses>::Un;
|
||||
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &x) {
|
||||
|
@ -211,14 +174,14 @@ public:
|
|||
Expr(std::uint64_t n) : u_{Scalar{n}} {}
|
||||
Expr(int n) : u_{Scalar{n}} {}
|
||||
template<int K>
|
||||
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{GenericIntegerExpr{x}}} {}
|
||||
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{AnyKindIntegerExpr{x}}} {}
|
||||
template<int K>
|
||||
Expr(IntegerExpr<K> &&x)
|
||||
: u_{ConvertInteger{GenericIntegerExpr{std::move(x)}}} {}
|
||||
: u_{ConvertInteger{AnyKindIntegerExpr{std::move(x)}}} {}
|
||||
template<int K>
|
||||
Expr(const RealExpr<K> &x) : u_{ConvertReal{GenericRealExpr{x}}} {}
|
||||
Expr(const RealExpr<K> &x) : u_{ConvertReal{AnyKindRealExpr{x}}} {}
|
||||
template<int K>
|
||||
Expr(RealExpr<K> &&x) : u_{ConvertReal{GenericRealExpr{std::move(x)}}} {}
|
||||
Expr(RealExpr<K> &&x) : u_{ConvertReal{AnyKindRealExpr{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> &&
|
||||
|
@ -249,23 +212,19 @@ public:
|
|||
// and part access operations (resp.). Conversions between kinds of
|
||||
// Complex are done via decomposition to Real and reconstruction.
|
||||
struct ConvertInteger
|
||||
: public Unary<ConvertInteger, Result, GenericIntegerExpr,
|
||||
CategoryScalar<Category::Integer>> {
|
||||
using Unary<ConvertInteger, Result, GenericIntegerExpr,
|
||||
CategoryScalar<Category::Integer>>::Unary;
|
||||
: public Unary<ConvertInteger, Result, AnyKindType<Category::Integer>> {
|
||||
using Unary<ConvertInteger, Result, AnyKindType<Category::Integer>>::Unary;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const CategoryScalar<Category::Integer> &);
|
||||
FoldingContext &, const ScalarConstant<Category::Integer> &);
|
||||
};
|
||||
struct ConvertReal : public Unary<ConvertReal, Result, GenericRealExpr,
|
||||
CategoryScalar<Category::Real>> {
|
||||
using Unary<ConvertReal, Result, GenericRealExpr,
|
||||
CategoryScalar<Category::Real>>::Unary;
|
||||
struct ConvertReal
|
||||
: public Unary<ConvertReal, Result, AnyKindType<Category::Real>> {
|
||||
using Unary<ConvertReal, Result, AnyKindType<Category::Real>>::Unary;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const CategoryScalar<Category::Real> &);
|
||||
FoldingContext &, const ScalarConstant<Category::Real> &);
|
||||
};
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result, Expr, Scalar>;
|
||||
template<typename CRTP>
|
||||
using Bin = Binary<CRTP, Result, Expr, Expr, Scalar, Scalar>;
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result>;
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Parentheses : public Un<Parentheses> {
|
||||
using Un<Parentheses>::Un;
|
||||
};
|
||||
|
@ -287,10 +246,10 @@ public:
|
|||
struct Power : public Bin<Power> {
|
||||
using Bin<Power>::Bin;
|
||||
};
|
||||
struct IntPower : public Binary<IntPower, Result, Expr, GenericIntegerExpr,
|
||||
Scalar, CategoryScalar<Category::Integer>> {
|
||||
using Binary<IntPower, Result, Expr, GenericIntegerExpr, Scalar,
|
||||
CategoryScalar<Category::Integer>>::Binary;
|
||||
struct IntPower
|
||||
: public Binary<IntPower, Result, Result, AnyKindType<Category::Integer>> {
|
||||
using Binary<IntPower, Result, Result,
|
||||
AnyKindType<Category::Integer>>::Binary;
|
||||
};
|
||||
struct Max : public Bin<Max> {
|
||||
using Bin<Max>::Bin;
|
||||
|
@ -299,8 +258,7 @@ public:
|
|||
using Bin<Min>::Bin;
|
||||
};
|
||||
template<typename CRTP>
|
||||
using CplxUn = Unary<CRTP, Result, ComplexExpr<KIND>,
|
||||
typename Type<Category::Complex, KIND>::Value>;
|
||||
using CplxUn = Unary<CRTP, Result, Type<Category::Complex, KIND>>;
|
||||
struct RealPart : public CplxUn<RealPart> {
|
||||
using CplxUn<RealPart>::CplxUn;
|
||||
};
|
||||
|
@ -311,14 +269,14 @@ public:
|
|||
CLASS_BOILERPLATE(Expr)
|
||||
Expr(const Scalar &x) : u_{x} {}
|
||||
template<int K>
|
||||
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{GenericIntegerExpr{x}}} {}
|
||||
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{AnyKindIntegerExpr{x}}} {}
|
||||
template<int K>
|
||||
Expr(IntegerExpr<K> &&x)
|
||||
: u_{ConvertInteger{GenericIntegerExpr{std::move(x)}}} {}
|
||||
: u_{ConvertInteger{AnyKindIntegerExpr{std::move(x)}}} {}
|
||||
template<int K>
|
||||
Expr(const RealExpr<K> &x) : u_{ConvertReal{GenericRealExpr{x}}} {}
|
||||
Expr(const RealExpr<K> &x) : u_{ConvertReal{AnyKindRealExpr{x}}} {}
|
||||
template<int K>
|
||||
Expr(RealExpr<K> &&x) : u_{ConvertReal{GenericRealExpr{std::move(x)}}} {}
|
||||
Expr(RealExpr<K> &&x) : u_{ConvertReal{AnyKindRealExpr{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)} {}
|
||||
|
@ -342,9 +300,8 @@ public:
|
|||
using Result = Type<Category::Complex, KIND>;
|
||||
using Scalar = typename Result::Value;
|
||||
using FoldableTrait = std::true_type;
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result, Expr, Scalar>;
|
||||
template<typename CRTP>
|
||||
using Bin = Binary<CRTP, Result, Expr, Expr, Scalar, Scalar>;
|
||||
template<typename CRTP> using Un = Unary<CRTP, Result>;
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Parentheses : public Un<Parentheses> {
|
||||
using Un<Parentheses>::Un;
|
||||
};
|
||||
|
@ -366,15 +323,12 @@ public:
|
|||
struct Power : public Bin<Power> {
|
||||
using Bin<Power>::Bin;
|
||||
};
|
||||
struct IntPower : public Binary<IntPower, Result, Expr, GenericIntegerExpr,
|
||||
Scalar, CategoryScalar<Category::Integer>> {
|
||||
using Binary<IntPower, Result, Expr, GenericIntegerExpr, Scalar,
|
||||
CategoryScalar<Category::Integer>>::Binary;
|
||||
struct IntPower
|
||||
: public Binary<IntPower, Result, AnyKindType<Category::Integer>> {
|
||||
using Binary<IntPower, Result, AnyKindType<Category::Integer>>::Binary;
|
||||
};
|
||||
struct CMPLX : public Binary<CMPLX, Result, RealExpr<KIND>, RealExpr<KIND>,
|
||||
typename Scalar::Part, typename Scalar::Part> {
|
||||
using Binary<CMPLX, Result, RealExpr<KIND>, RealExpr<KIND>,
|
||||
typename Scalar::Part, typename Scalar::Part>::Binary;
|
||||
struct CMPLX : public Binary<CMPLX, Result, Type<Category::Real, KIND>> {
|
||||
using Binary<CMPLX, Result, Type<Category::Real, KIND>>::Binary;
|
||||
};
|
||||
|
||||
CLASS_BOILERPLATE(Expr)
|
||||
|
@ -401,8 +355,7 @@ public:
|
|||
using Result = Type<Category::Character, KIND>;
|
||||
using Scalar = typename Result::Value;
|
||||
using FoldableTrait = std::true_type;
|
||||
template<typename CRTP>
|
||||
using Bin = Binary<CRTP, Result, Expr, Expr, Scalar, Scalar>;
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Concat : public Bin<Concat> {
|
||||
using Bin<Concat>::Bin;
|
||||
};
|
||||
|
@ -439,91 +392,103 @@ private:
|
|||
// categories and kinds of comparable operands.
|
||||
ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
|
||||
|
||||
template<typename EXPR>
|
||||
template<typename A>
|
||||
struct Comparison
|
||||
: public Binary<Comparison<EXPR>, Type<Category::Logical, 1>, EXPR, EXPR> {
|
||||
using Base = Binary<Comparison<EXPR>, Type<Category::Logical, 1>, EXPR, EXPR>;
|
||||
: public Binary<Comparison<A>, Type<Category::Logical, 1>, A> {
|
||||
using Base = Binary<Comparison, Type<Category::Logical, 1>, A>;
|
||||
using typename Base::Scalar;
|
||||
using OperandScalarConstant = typename Base::LeftScalar;
|
||||
CLASS_BOILERPLATE(Comparison)
|
||||
Comparison(RelationalOperator r, const EXPR &a, const EXPR &b)
|
||||
Comparison(RelationalOperator r, const Expr<A> &a, const Expr<A> &b)
|
||||
: Base{a, b}, opr{r} {}
|
||||
Comparison(RelationalOperator r, EXPR &&a, EXPR &&b)
|
||||
Comparison(RelationalOperator r, Expr<A> &&a, Expr<A> &&b)
|
||||
: Base{std::move(a), std::move(b)}, opr{r} {}
|
||||
std::optional<bool> FoldScalar(FoldingContext &c,
|
||||
const typename Base::LeftScalar &, const typename Base::RightScalar &);
|
||||
std::optional<Scalar> FoldScalar(FoldingContext &c,
|
||||
const OperandScalarConstant &, const OperandScalarConstant &);
|
||||
RelationalOperator opr;
|
||||
};
|
||||
|
||||
extern template struct Comparison<IntegerExpr<1>>;
|
||||
extern template struct Comparison<IntegerExpr<2>>;
|
||||
extern template struct Comparison<IntegerExpr<4>>;
|
||||
extern template struct Comparison<IntegerExpr<8>>;
|
||||
extern template struct Comparison<IntegerExpr<16>>;
|
||||
extern template struct Comparison<RealExpr<2>>;
|
||||
extern template struct Comparison<RealExpr<4>>;
|
||||
extern template struct Comparison<RealExpr<8>>;
|
||||
extern template struct Comparison<RealExpr<10>>;
|
||||
extern template struct Comparison<RealExpr<16>>;
|
||||
extern template struct Comparison<ComplexExpr<2>>;
|
||||
extern template struct Comparison<ComplexExpr<4>>;
|
||||
extern template struct Comparison<ComplexExpr<8>>;
|
||||
extern template struct Comparison<ComplexExpr<10>>;
|
||||
extern template struct Comparison<ComplexExpr<16>>;
|
||||
extern template struct Comparison<CharacterExpr<1>>;
|
||||
extern template struct Comparison<Type<Category::Integer, 1>>;
|
||||
extern template struct Comparison<Type<Category::Integer, 2>>;
|
||||
extern template struct Comparison<Type<Category::Integer, 4>>;
|
||||
extern template struct Comparison<Type<Category::Integer, 8>>;
|
||||
extern template struct Comparison<Type<Category::Integer, 16>>;
|
||||
extern template struct Comparison<Type<Category::Real, 2>>;
|
||||
extern template struct Comparison<Type<Category::Real, 4>>;
|
||||
extern template struct Comparison<Type<Category::Real, 8>>;
|
||||
extern template struct Comparison<Type<Category::Real, 10>>;
|
||||
extern template struct Comparison<Type<Category::Real, 16>>;
|
||||
extern template struct Comparison<Type<Category::Complex, 2>>;
|
||||
extern template struct Comparison<Type<Category::Complex, 4>>;
|
||||
extern template struct Comparison<Type<Category::Complex, 8>>;
|
||||
extern template struct Comparison<Type<Category::Complex, 10>>;
|
||||
extern template struct Comparison<Type<Category::Complex, 16>>;
|
||||
extern template struct Comparison<Type<Category::Character, 1>>;
|
||||
|
||||
// Dynamically polymorphic comparisons whose operands are expressions of
|
||||
// the same supported kind of a particular type category.
|
||||
template<Category CAT> struct CategoryComparison {
|
||||
using Scalar = typename Type<Category::Logical, 1>::Value;
|
||||
CLASS_BOILERPLATE(CategoryComparison)
|
||||
template<int KIND> using KindComparison = Comparison<Expr<Type<CAT, KIND>>>;
|
||||
template<int KIND> using KindComparison = Comparison<Type<CAT, KIND>>;
|
||||
template<int KIND> CategoryComparison(const KindComparison<KIND> &x) : u{x} {}
|
||||
template<int KIND>
|
||||
CategoryComparison(KindComparison<KIND> &&x) : u{std::move(x)} {}
|
||||
std::optional<bool> Fold(FoldingContext &c);
|
||||
std::optional<Scalar> Fold(FoldingContext &c);
|
||||
typename KindsVariant<CAT, KindComparison>::type u;
|
||||
};
|
||||
|
||||
// No need to distinguish the various kinds of LOGICAL expression results.
|
||||
template<> class Expr<Type<Category::Logical, 1>> {
|
||||
template<int KIND> class Expr<Type<Category::Logical, KIND>> {
|
||||
public:
|
||||
using Result = Type<Category::Logical, 1>;
|
||||
using Scalar = bool;
|
||||
using Result = Type<Category::Logical, KIND>;
|
||||
using Scalar = typename Result::Value;
|
||||
using FoldableTrait = std::true_type;
|
||||
struct Not : Unary<Not, Result, Expr, bool> {
|
||||
using Unary<Not, Result, Expr, bool>::Unary;
|
||||
struct Not : Unary<Not, Result> {
|
||||
using Unary<Not, Result>::Unary;
|
||||
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &);
|
||||
};
|
||||
template<typename CRTP>
|
||||
using Bin = Binary<CRTP, Result, Expr, Expr, bool, bool>;
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct And : public Bin<And> {
|
||||
using Bin<And>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct Or : public Bin<Or> {
|
||||
using Bin<Or>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct Eqv : public Bin<Eqv> {
|
||||
using Bin<Eqv>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct Neqv : public Bin<Neqv> {
|
||||
using Bin<Neqv>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
|
||||
CLASS_BOILERPLATE(Expr)
|
||||
Expr(bool x) : u_{x} {}
|
||||
template<Category CAT, int KIND>
|
||||
Expr(const Comparison<Expr<Type<CAT, KIND>>> &x)
|
||||
: u_{CategoryComparison<CAT>{x}} {}
|
||||
template<Category CAT, int KIND>
|
||||
Expr(Comparison<Expr<Type<CAT, KIND>>> &&x)
|
||||
Expr(const Scalar &x) : u_{x} {}
|
||||
Expr(bool x) : u_{Scalar{x}} {}
|
||||
template<Category CAT, int K>
|
||||
Expr(const Comparison<Type<CAT, K>> &x) : u_{CategoryComparison<CAT>{x}} {}
|
||||
template<Category CAT, int K>
|
||||
Expr(Comparison<Type<CAT, K>> &&x)
|
||||
: u_{CategoryComparison<CAT>{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<bool> ScalarValue() const { return common::GetIf<bool>(u_); }
|
||||
std::optional<Scalar> ScalarValue() const {
|
||||
return common::GetIf<Scalar>(u_);
|
||||
}
|
||||
std::optional<Scalar> Fold(FoldingContext &c);
|
||||
|
||||
private:
|
||||
std::variant<bool, CopyableIndirection<DataRef>,
|
||||
std::variant<Scalar, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<FunctionRef>, Not, And, Or, Eqv, Neqv,
|
||||
CategoryComparison<Category::Integer>, CategoryComparison<Category::Real>,
|
||||
CategoryComparison<Category::Complex>,
|
||||
|
@ -548,22 +513,32 @@ extern template class Expr<Type<Category::Complex, 10>>;
|
|||
extern template class Expr<Type<Category::Complex, 16>>;
|
||||
extern template class Expr<Type<Category::Character, 1>>;
|
||||
extern template class Expr<Type<Category::Logical, 1>>;
|
||||
extern template class Expr<Type<Category::Logical, 2>>;
|
||||
extern template class Expr<Type<Category::Logical, 4>>;
|
||||
extern template class Expr<Type<Category::Logical, 8>>;
|
||||
|
||||
// Dynamically polymorphic expressions that can hold any supported kind
|
||||
// of a specific intrinsic type category.
|
||||
template<Category CAT> struct CategoryExpr {
|
||||
static constexpr Category category{CAT};
|
||||
using Scalar = CategoryScalar<CAT>;
|
||||
template<Category CAT> class Expr<AnyKindType<CAT>> {
|
||||
public:
|
||||
using Result = AnyKindType<CAT>;
|
||||
using Scalar = typename Result::Value;
|
||||
using FoldableTrait = std::true_type;
|
||||
CLASS_BOILERPLATE(CategoryExpr)
|
||||
CLASS_BOILERPLATE(Expr)
|
||||
template<int KIND> using KindExpr = Expr<Type<CAT, KIND>>;
|
||||
template<int KIND> CategoryExpr(const KindExpr<KIND> &x) : u{x} {}
|
||||
template<int KIND> CategoryExpr(KindExpr<KIND> &&x) : u{std::move(x)} {}
|
||||
template<int KIND> Expr(const KindExpr<KIND> &x) : u{x} {}
|
||||
template<int KIND> Expr(KindExpr<KIND> &&x) : u{std::move(x)} {}
|
||||
std::optional<Scalar> ScalarValue() const;
|
||||
std::optional<Scalar> Fold(FoldingContext &);
|
||||
typename KindsVariant<CAT, KindExpr>::type u;
|
||||
};
|
||||
|
||||
extern template class Expr<AnyKindType<Category::Integer>>;
|
||||
extern template class Expr<AnyKindType<Category::Real>>;
|
||||
extern template class Expr<AnyKindType<Category::Complex>>;
|
||||
extern template class Expr<AnyKindType<Category::Character>>;
|
||||
extern template class Expr<AnyKindType<Category::Logical>>;
|
||||
|
||||
// A completely generic expression, polymorphic across the intrinsic type
|
||||
// categories and each of their kinds.
|
||||
struct GenericExpr {
|
||||
|
@ -571,9 +546,10 @@ struct GenericExpr {
|
|||
using FoldableTrait = std::true_type;
|
||||
CLASS_BOILERPLATE(GenericExpr)
|
||||
template<Category CAT, int KIND>
|
||||
GenericExpr(const Expr<Type<CAT, KIND>> &x) : u{CategoryExpr<CAT>{x}} {}
|
||||
GenericExpr(const Expr<Type<CAT, KIND>> &x) : u{Expr<AnyKindType<CAT>>{x}} {}
|
||||
template<Category CAT, int KIND>
|
||||
GenericExpr(Expr<Type<CAT, KIND>> &&x) : u{CategoryExpr<CAT>{std::move(x)}} {}
|
||||
GenericExpr(Expr<Type<CAT, KIND>> &&x)
|
||||
: u{Expr<AnyKindType<CAT>>{std::move(x)}} {}
|
||||
template<typename A> GenericExpr(const A &x) : u{x} {}
|
||||
template<typename A>
|
||||
GenericExpr(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
|
@ -581,8 +557,8 @@ struct GenericExpr {
|
|||
std::optional<Scalar> ScalarValue() const;
|
||||
std::optional<Scalar> Fold(FoldingContext &);
|
||||
int Rank() const { return 1; } // TODO
|
||||
std::variant<GenericIntegerExpr, GenericRealExpr, GenericComplexExpr,
|
||||
GenericCharacterExpr, LogicalExpr>
|
||||
std::variant<AnyKindIntegerExpr, AnyKindRealExpr, AnyKindComplexExpr,
|
||||
AnyKindCharacterExpr, AnyKindLogicalExpr>
|
||||
u;
|
||||
};
|
||||
|
||||
|
@ -621,22 +597,23 @@ BINARY(Power, Power)
|
|||
#undef BINARY
|
||||
|
||||
#define BINARY(FUNC, OP) \
|
||||
template<typename A> LogicalExpr FUNC(const A &x, const A &y) { \
|
||||
return {Comparison<A>{OP, x, y}}; \
|
||||
template<typename A> LogicalExpr<1> FUNC(const A &x, const A &y) { \
|
||||
return {Comparison<typename A::Result>{OP, x, y}}; \
|
||||
} \
|
||||
template<typename A> \
|
||||
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr> FUNC( \
|
||||
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr<1>> FUNC( \
|
||||
const A &x, A &&y) { \
|
||||
return {Comparison<A>{OP, x, std::move(y)}}; \
|
||||
return {Comparison<typename A::Result>{OP, x, std::move(y)}}; \
|
||||
} \
|
||||
template<typename A> \
|
||||
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr> FUNC( \
|
||||
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr<1>> FUNC( \
|
||||
A &&x, const A &y) { \
|
||||
return {Comparison<A>{OP, std::move(x), y}}; \
|
||||
return {Comparison<typename A::Result>{OP, std::move(x), y}}; \
|
||||
} \
|
||||
template<typename A> \
|
||||
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr> FUNC(A &&x, A &&y) { \
|
||||
return {Comparison<A>{OP, std::move(x), std::move(y)}}; \
|
||||
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr<1>> FUNC( \
|
||||
A &&x, A &&y) { \
|
||||
return {Comparison<typename A::Result>{OP, std::move(x), std::move(y)}}; \
|
||||
}
|
||||
|
||||
BINARY(operator<, RelationalOperator::LT)
|
||||
|
|
|
@ -24,7 +24,9 @@ template<int BITS> class Logical {
|
|||
public:
|
||||
static constexpr int bits{BITS};
|
||||
constexpr Logical() {} // .FALSE.
|
||||
constexpr Logical(const Logical &that) = default;
|
||||
constexpr Logical(bool truth) : word_{-std::uint64_t{truth}} {}
|
||||
constexpr Logical &operator=(const Logical &) = default;
|
||||
|
||||
// For static expression evaluation, all the bits will have the same value.
|
||||
constexpr bool IsTrue() const { return word_.BTEST(0); }
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
ENUM_CLASS(Category, Integer, Real, Complex, Logical, Character, Derived)
|
||||
ENUM_CLASS(Category, Integer, Real, Complex, Character, Logical, Derived)
|
||||
|
||||
template<Category C, int KIND> struct TypeBase {
|
||||
static constexpr Category category{C};
|
||||
|
@ -84,12 +84,6 @@ struct Type<Category::Complex, KIND>
|
|||
using Value = value::Complex<typename Part::Value>;
|
||||
};
|
||||
|
||||
template<int KIND>
|
||||
struct Type<Category::Logical, KIND>
|
||||
: public TypeBase<Category::Logical, KIND> {
|
||||
using Value = value::Logical<8 * KIND>;
|
||||
};
|
||||
|
||||
template<int KIND> struct Type<Category::Character, KIND> {
|
||||
static constexpr Category category{Category::Character};
|
||||
static constexpr int kind{KIND};
|
||||
|
@ -100,6 +94,12 @@ template<int KIND> struct Type<Category::Character, KIND> {
|
|||
}
|
||||
};
|
||||
|
||||
template<int KIND>
|
||||
struct Type<Category::Logical, KIND>
|
||||
: public TypeBase<Category::Logical, KIND> {
|
||||
using Value = value::Logical<8 * KIND>;
|
||||
};
|
||||
|
||||
// Default REAL just simply has to be IEEE-754 single precision today.
|
||||
// It occupies one numeric storage unit by definition. The default INTEGER
|
||||
// and default LOGICAL intrinsic types also have to occupy one numeric
|
||||
|
@ -119,10 +119,11 @@ using SubscriptInteger = Type<Category::Integer, 8>;
|
|||
|
||||
// These macros invoke other macros on each of the supported kinds of
|
||||
// a given category.
|
||||
// TODO larger CHARACTER kinds, incl. Kanji
|
||||
#define COMMA ,
|
||||
#define FOR_EACH_INTEGER_KIND(M, SEP) M(1) SEP M(2) SEP M(4) SEP M(8) SEP M(16)
|
||||
#define FOR_EACH_REAL_KIND(M, SEP) M(2) SEP M(4) SEP M(8) SEP M(10) SEP M(16)
|
||||
#define FOR_EACH_COMPLEX_KIND(M, SEP) FOR_EACH_REAL_KIND(M, SEP)
|
||||
#define FOR_EACH_COMPLEX_KIND(M, SEP) M(2) SEP M(4) SEP M(8) SEP M(10) SEP M(16)
|
||||
#define FOR_EACH_CHARACTER_KIND(M, SEP) M(1)
|
||||
#define FOR_EACH_LOGICAL_KIND(M, SEP) M(1) SEP M(2) SEP M(4) SEP M(8)
|
||||
|
||||
|
@ -134,19 +135,55 @@ template<Category CAT, template<int> class T> struct KindsVariant;
|
|||
template<template<int> class T> struct KindsVariant<Category::Integer, T> {
|
||||
using type = std::variant<FOR_EACH_INTEGER_KIND(TKIND, COMMA)>;
|
||||
};
|
||||
// TODO use FOR_EACH...
|
||||
template<template<int> class T> struct KindsVariant<Category::Real, T> {
|
||||
using type = std::variant<T<2>, T<4>, T<8>, T<10>, T<16>>;
|
||||
using type = std::variant<FOR_EACH_REAL_KIND(TKIND, COMMA)>;
|
||||
};
|
||||
template<template<int> class T> struct KindsVariant<Category::Complex, T> {
|
||||
using type = typename KindsVariant<Category::Real, T>::type;
|
||||
using type = std::variant<FOR_EACH_COMPLEX_KIND(TKIND, COMMA)>;
|
||||
};
|
||||
template<template<int> class T> struct KindsVariant<Category::Character, T> {
|
||||
using type = std::variant<T<1>>; // TODO larger CHARACTER kinds, incl. Kanji
|
||||
using type = std::variant<FOR_EACH_CHARACTER_KIND(TKIND, COMMA)>;
|
||||
};
|
||||
template<template<int> class T> struct KindsVariant<Category::Logical, T> {
|
||||
using type = std::variant<T<1>, T<2>, T<4>, T<8>>;
|
||||
using type = std::variant<FOR_EACH_LOGICAL_KIND(TKIND, COMMA)>;
|
||||
};
|
||||
#undef TKIND
|
||||
|
||||
// Holds a scalar constant of any kind within a particular intrinsic type
|
||||
// category.
|
||||
template<Category CAT> struct ScalarConstant {
|
||||
CLASS_BOILERPLATE(ScalarConstant)
|
||||
template<int KIND> using KindScalar = typename Type<CAT, KIND>::Value;
|
||||
template<typename A> ScalarConstant(const A &x) : u{x} {}
|
||||
template<typename A>
|
||||
ScalarConstant(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
: u{std::move(x)} {}
|
||||
typename KindsVariant<CAT, KindScalar>::type u;
|
||||
};
|
||||
|
||||
// Holds a scalar constant of any intrinsic category and size.
|
||||
struct GenericScalar {
|
||||
CLASS_BOILERPLATE(GenericScalar)
|
||||
template<Category CAT, int KIND>
|
||||
GenericScalar(const typename Type<CAT, KIND>::Value &x)
|
||||
: u{ScalarConstant<CAT>{x}} {}
|
||||
template<Category CAT, int KIND>
|
||||
GenericScalar(typename Type<CAT, KIND>::Value &&x)
|
||||
: u{ScalarConstant<CAT>{std::move(x)}} {}
|
||||
template<typename A> GenericScalar(const A &x) : u{x} {}
|
||||
template<typename A>
|
||||
GenericScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
: u{std::move(x)} {}
|
||||
std::variant<ScalarConstant<Category::Integer>,
|
||||
ScalarConstant<Category::Real>, ScalarConstant<Category::Complex>,
|
||||
ScalarConstant<Category::Character>, ScalarConstant<Category::Logical>>
|
||||
u;
|
||||
};
|
||||
|
||||
// Represents a type that any supported kind within a particular category.
|
||||
template<Category CAT> struct AnyKindType {
|
||||
static constexpr Category category{CAT};
|
||||
using Value = ScalarConstant<CAT>;
|
||||
};
|
||||
} // namespace Fortran::evaluate
|
||||
#endif // FORTRAN_EVALUATE_TYPE_H_
|
||||
|
|
|
@ -57,7 +57,7 @@ std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
|||
ExpressionAnalyzer &ea, const parser::Integer<A> &tree) {
|
||||
std::optional<evaluate::GenericExpr> result{AnalyzeHelper(ea, tree.thing)};
|
||||
if (result.has_value() &&
|
||||
!std::holds_alternative<evaluate::GenericIntegerExpr>(result->u)) {
|
||||
!std::holds_alternative<evaluate::AnyKindIntegerExpr>(result->u)) {
|
||||
ea.Say("must be integer"_err_en_US);
|
||||
return {};
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ std::optional<evaluate::GenericExpr> AnalyzeHelper(
|
|||
#define CASE(k) \
|
||||
case k: \
|
||||
return {evaluate::GenericExpr{ \
|
||||
evaluate::GenericIntegerExpr{evaluate::IntegerExpr<k>{value}}}};
|
||||
evaluate::AnyKindIntegerExpr{evaluate::IntegerExpr<k>{value}}}};
|
||||
FOR_EACH_INTEGER_KIND(CASE, )
|
||||
#undef CASE
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue