From 7d042acb9dbbd5bdc5cdc295deb3bb1741ab748a Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 23 Aug 2018 14:49:28 -0700 Subject: [PATCH] [flang] continue refactoring Original-commit: flang-compiler/f18@f2b49ba0e23a6281f9e850611712bdbb32af3334 Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false --- flang/lib/common/idioms.h | 7 ++ flang/lib/common/template.h | 68 ++++++++++++----- flang/lib/evaluate/expression.cc | 13 ++-- flang/lib/evaluate/expression.h | 24 ++---- flang/lib/evaluate/tools.cc | 5 +- flang/lib/evaluate/tools.h | 7 -- flang/lib/evaluate/type.h | 153 +++++++++++++++++++-------------------- 7 files changed, 150 insertions(+), 127 deletions(-) diff --git a/flang/lib/common/idioms.h b/flang/lib/common/idioms.h index 8a97c1e..caebc4e 100644 --- a/flang/lib/common/idioms.h +++ b/flang/lib/common/idioms.h @@ -173,5 +173,12 @@ std::optional MapOptional(std::function &f, return std::nullopt; } +// Move a value from one variant type to another. The types allowed in the +// source variant must all be allowed in the destination variant type. +template TOV MoveVariant(FROMV &&u) { + return std::visit( + [](auto &&x) -> TOV { return {std::move(x)}; }, std::move(u)); +} + } // namespace Fortran::common #endif // FORTRAN_COMMON_IDIOMS_H_ diff --git a/flang/lib/common/template.h b/flang/lib/common/template.h index 62db722..fa2f77a 100644 --- a/flang/lib/common/template.h +++ b/flang/lib/common/template.h @@ -27,23 +27,22 @@ namespace Fortran::common { // SearchTypeList scans a list of types. The zero-based // index of the first type T in the list for which PREDICATE::value() is // true is returned, or -1 if the predicate is false for every type in the list. -template class PREDICATE, typename A, - typename... REST> -struct SearchTypeListTemplate { +template class PREDICATE, typename TUPLE> +struct SearchTypeListHelper { static constexpr int value() { - if constexpr (PREDICATE::value()) { - return N; - } else if constexpr (sizeof...(REST) == 0) { + if constexpr (N >= std::tuple_size_v) { return -1; + } else if constexpr (PREDICATE>::value()) { + return N; } else { - return SearchTypeListTemplate::value(); + return SearchTypeListHelper::value(); } } }; template class PREDICATE, typename... TYPES> constexpr int SearchTypeList{ - SearchTypeListTemplate<0, PREDICATE, TYPES...>::value()}; + SearchTypeListHelper<0, PREDICATE, std::tuple>::value()}; // TypeIndex scans a list of types for simple type equality. // The zero-based index of A in the list is returned, or -1 if A is not present. @@ -66,17 +65,31 @@ constexpr int TypeIndex{SearchTypeList::template Match, TYPES...>}; // N.B. It *is* possible to extract the types of the alternatives of a // std::variant discriminated union instantiation and reuse them as a // template parameter pack in another template instantiation. The trick is -// to match the std::variant type with a partial specialization. -template class PREDICATE, typename V> -struct SearchVariantTypeTemplate; -template class PREDICATE, typename... Ts> -struct SearchVariantTypeTemplate> { - static constexpr int index{SearchTypeList}; +// to match the std::variant type with a partial specialization. And it +// works with tuples, too, of course. +template class, typename> struct OverMembersHelper; +template class T, typename... Ts> +struct OverMembersHelper> { + using type = T; +}; +template class T, typename... Ts> +struct OverMembersHelper> { + using type = T; +}; + +template class T, typename TorV> +using OverMembers = typename OverMembersHelper::type; + +template class PREDICATE> struct SearchMembersHelper { + template struct Scanner { + static constexpr int value() { return SearchTypeList; } + }; }; -template class PREDICATE, typename VARIANT> -constexpr int SearchVariantType{ - SearchVariantTypeTemplate::index}; +template class PREDICATE, typename TorV> +constexpr int SearchMembers{ + OverMembers::template Scanner, + TorV>::value()}; // CombineTuples takes a list of std::tuple<> template instantiation types // and constructs a new std::tuple type that concatenates all of their member @@ -93,7 +106,8 @@ template using CombineTuples = typename CombineTuplesHelper::type; // CombineVariants takes a list of std::variant<> instantiations and constructs -// a new instantiation that holds all of their alternatives. +// a new instantiation that holds all of their alternatives, which probably +// should be distinct. template struct VariantToTupleHelper; template struct VariantToTupleHelper> { using type = std::tuple; @@ -114,5 +128,23 @@ template struct CombineVariantsHelper { template using CombineVariants = typename CombineVariantsHelper::type; +// Given a type function, apply it to each of the types in a tuple or variant, +// and collect the results in another tuple or variant. +template class, template class, typename...> +struct MapTemplateHelper; +template class F, template class TorV, + typename... Ts> +struct MapTemplateHelper> { + using type = TorV...>; +}; +template class F, template class TorV, + typename... Ts> +struct MapTemplateHelper> { + using type = TorV...>; +}; +template class F, template class TorV, + typename TV> +using MapTemplate = typename MapTemplateHelper::type; + } // namespace Fortran::common #endif // FORTRAN_COMMON_TEMPLATE_H_ diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 1fe6544..e5c57bc 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -191,7 +191,7 @@ auto Expr::Fold(FoldingContext &context) }, [&](auto &x) -> std::optional> { if (auto c{x.Fold(context)}) { - return {Scalar{std::move(*c)}}; + return {common::MoveVariant>(std::move(c->u))}; } return std::nullopt; }}, @@ -229,7 +229,7 @@ auto Convert::FoldScalar(FoldingContext &context, using Ty = TypeOf>; return Convert::FoldScalar(context, x); }, - c.u.u); + c.u); } else if constexpr (Result::category == TypeCategory::Integer) { if constexpr (Operand::category == TypeCategory::Integer) { auto converted{Scalar::ConvertSigned(c)}; @@ -398,7 +398,7 @@ auto RealToIntPower::FoldScalar(FoldingContext &context, RealFlagWarnings(context, power.flags, "raising to INTEGER power"); return {std::move(power.value)}; }, - y.u.u); + y.u); } template @@ -543,9 +543,8 @@ std::ostream &Expr>::Dump(std::ostream &o) const { return DumpExpr(o, u.u); } -template -std::ostream &Relational>::Dump(std::ostream &o) const { - return DumpExpr(o, u.u); +std::ostream &AnyRelational::Dump(std::ostream &o) const { + return DumpExpr(o, u); } std::ostream &Expr::Dump(std::ostream &o) const { @@ -669,7 +668,7 @@ auto Expr::ScalarValue() const -> std::optional> { }, [](const auto &x) -> std::optional> { if (auto c{x.ScalarValue()}) { - return {Scalar{std::move(*c)}}; + return {common::MoveVariant>(std::move(c->u))}; } return std::nullopt; }}, diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index 97e4790..831cc0c 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -497,22 +497,16 @@ struct Relational : public Operation, LogicalResult, A, A> { // A generic relation between two operands of the same kind in some intrinsic // type category (except LOGICAL). -template struct Relational> { - static constexpr TypeCategory category{CAT}; +struct AnyRelational { using Result = LogicalResult; - using Operand = SomeKind; - template using KindRelational = Relational>; - - CLASS_BOILERPLATE(Relational) - template - Relational(const KindRelational &x) : u{x} {} - template - Relational(KindRelational &&x) : u{std::move(x)} {} - + template AnyRelational(const A &x) : u{x} {} + template + AnyRelational(std::enable_if_t, A> &&x) + : u{std::move(x)} {} std::optional> Fold(FoldingContext &); std::ostream &Dump(std::ostream &) const; - CategoryUnion u; + common::MapTemplate u; }; template class Expr> { @@ -544,11 +538,7 @@ private: std::variant, CopyableIndirection, CopyableIndirection, // TODO Parentheses, - Not, LogicalOperation, - Relational>, - Relational>, - Relational>, - Relational>> + Not, LogicalOperation, AnyRelational> u_; }; diff --git a/flang/lib/evaluate/tools.cc b/flang/lib/evaluate/tools.cc index a3a03a8..4f486de 100644 --- a/flang/lib/evaluate/tools.cc +++ b/flang/lib/evaluate/tools.cc @@ -67,7 +67,10 @@ ConvertRealOperandsResult ConvertRealOperands( Expr GenericScalarToExpr(const Scalar &x) { return std::visit( - [&](const auto &c) { return ToGenericExpr(SomeKindScalarToExpr(c)); }, + [](const auto &c) -> Expr { + using Ty = TypeOf; + return {Expr>{Expr{c}}}; + }, x.u); } diff --git a/flang/lib/evaluate/tools.h b/flang/lib/evaluate/tools.h index 9996a8a..1581e63 100644 --- a/flang/lib/evaluate/tools.h +++ b/flang/lib/evaluate/tools.h @@ -141,13 +141,6 @@ Expr> ToSomeKindExpr(Expr> &&x) { return {std::move(x)}; } -template -Expr> SomeKindScalarToExpr(const SomeKindScalar &x) { - return std::visit( - [](const auto &c) { return ToSomeKindExpr(ScalarConstantToExpr(c)); }, - x.u.u); -} - Expr GenericScalarToExpr(const Scalar &); template diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index dd9bd6b..cb585ba 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -112,6 +112,7 @@ struct Type template using Scalar = typename std::decay_t::Scalar; +// Given a specific type, find the type of the same kind in another category. template using SameKind = Type::kind>; @@ -194,104 +195,102 @@ struct IntrinsicTypeUnionTemplate { template class A> using IntrinsicTypeUnion = typename IntrinsicTypeUnionTemplate::type; +// For an intrinsic type category CAT, CategoryTypes is an instantiation +// of std::tuple> for every supported kind K in that category. +template +using CategoryTypesTuple = std::tuple...>; + +template struct CategoryTypesHelper; +template<> struct CategoryTypesHelper { + using type = CategoryTypesTuple; +}; +template<> struct CategoryTypesHelper { + using type = CategoryTypesTuple; +}; +template<> struct CategoryTypesHelper { + using type = CategoryTypesTuple; +}; +template<> struct CategoryTypesHelper { + using type = CategoryTypesTuple; // TODO: 2 & 4 +}; +template<> struct CategoryTypesHelper { + using type = CategoryTypesTuple; +}; +template +using CategoryTypes = typename CategoryTypesHelper::type; + +using NumericTypes = common::CombineTuples, + CategoryTypes, CategoryTypes>; +using RelationalTypes = + common::CombineTuples>; +using AllIntrinsicTypes = common::CombineTuples>; + // When Scalar is S, then TypeOf is T. // TypeOf is implemented by scanning all supported types for a match // with Type::Scalar. -template struct TypeOfTemplate { - template - struct InnerPredicate { // A is a specific Type +template struct TypeOfHelper { + template struct Predicate { static constexpr bool value() { return std::is_same_v, - std::decay_t>; + std::decay_t>; } }; - template - struct OuterPredicate { // A is a CategoryUnion - static constexpr bool value() { - return common::SearchVariantType >= - 0; - } - }; - using BareTypes = IntrinsicTypeUnion; - static constexpr int CatIndex{ - common::SearchVariantType}; - static_assert( - CatIndex >= 0 || !"no category found for type of scalar constant"); - static constexpr TypeCategory category{BareTypes::IndexToKind(CatIndex)}; - using CatType = BareTypes::template KindType; - static constexpr int KindIndex{ - common::SearchVariantType}; - static_assert(KindIndex >= 0 || !"search over category failed when repeated"); - static constexpr int kind{CatType::IndexToKind(KindIndex)}; - using type = Type; + static constexpr int index{ + common::SearchMembers}; + static_assert(index >= 0 || !"No intrinsic type found for constant type"); + using type = std::tuple_element_t; }; -template using TypeOf = typename TypeOfTemplate::type; +template using TypeOf = typename TypeOfHelper::type; -// Holds a scalar value of any kind within a particular intrinsic type -// category. -template struct SomeKindScalar { - static constexpr TypeCategory category{CAT}; - CLASS_BOILERPLATE(SomeKindScalar) +// A variant union that can hold a scalar constant of some type in a set. +template struct SomeScalar { + using Types = TYPES; + CLASS_BOILERPLATE(SomeScalar) - template SomeKindScalar(const A &x) : u{x} {} + template SomeScalar(const A &x) : u{x} {} template - SomeKindScalar(std::enable_if_t, A> &&x) + SomeScalar(std::enable_if_t, A> &&x) : u{std::move(x)} {} - std::optional ToInt64() const { - if constexpr (category == TypeCategory::Integer) { - return std::visit( - [](const auto &x) { return std::make_optional(x.ToInt64()); }, u.u); - } - return std::nullopt; + auto ToInt64() const { + return std::visit( + [](const auto &x) -> std::optional { + if constexpr (TypeOf::category == + TypeCategory::Integer) { + return {x.ToInt64()}; + } else { + return std::nullopt; + } + }, + u); } - std::optional ToString() const { - return common::GetIf(u.u); + auto ToString() const { + return std::visit( + [](const auto &x) -> std::optional { + if constexpr (std::is_same_v>) { + return {x}; + } else { + return std::nullopt; + } + }, + u); } - template using KindScalar = Scalar>; - CategoryUnion u; -}; - -// Holds a scalar constant of any intrinsic category and size. -struct GenericScalar { - CLASS_BOILERPLATE(GenericScalar) - - template - GenericScalar(const Scalar> &x) : u{SomeKindScalar{x}} {} - template - GenericScalar(Scalar> &&x) - : u{SomeKindScalar{std::move(x)}} {} - - template GenericScalar(const A &x) : u{x} {} - template - GenericScalar(std::enable_if_t, A> &&x) - : u{std::move(x)} {} - - std::optional ToInt64() const { - if (const auto *j{std::get_if>(&u)}) { - return j->ToInt64(); - } - return std::nullopt; - } - - std::optional ToString() const { - if (const auto *c{ - std::get_if>(&u)}) { - return c->ToString(); - } - return std::nullopt; + template auto GetIf() const { + return common::GetIf>(u); } - std::variant, - SomeKindScalar, SomeKindScalar, - SomeKindScalar, - SomeKindScalar> - u; + common::MapTemplate u; }; +template +using SomeKindScalar = SomeScalar>; +using GenericScalar = SomeScalar; + // Represents a type of any supported kind within a particular category. template struct SomeKind { using Scalar = SomeKindScalar; @@ -304,7 +303,7 @@ using SomeComplex = SomeKind; using SomeCharacter = SomeKind; using SomeLogical = SomeKind; -// Represents a completely generic type. +// Represents a completely generic intrinsic type. struct SomeType { using Scalar = GenericScalar; }; -- 2.7.4