[flang] continue refactoring

Original-commit: flang-compiler/f18@f2b49ba0e2
Reviewed-on: https://github.com/flang-compiler/f18/pull/183
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-08-23 14:49:28 -07:00
parent f38fe515ed
commit 7d042acb9d
7 changed files with 151 additions and 128 deletions

View File

@ -173,5 +173,12 @@ std::optional<A> MapOptional(std::function<A(B &&, C &&)> &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<typename TOV, typename FROMV> 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_

View File

@ -27,23 +27,22 @@ namespace Fortran::common {
// SearchTypeList<PREDICATE, TYPES...> scans a list of types. The zero-based
// index of the first type T in the list for which PREDICATE<T>::value() is
// true is returned, or -1 if the predicate is false for every type in the list.
template<int N, template<typename> class PREDICATE, typename A,
typename... REST>
struct SearchTypeListTemplate {
template<int N, template<typename> class PREDICATE, typename TUPLE>
struct SearchTypeListHelper {
static constexpr int value() {
if constexpr (PREDICATE<A>::value()) {
return N;
} else if constexpr (sizeof...(REST) == 0) {
if constexpr (N >= std::tuple_size_v<TUPLE>) {
return -1;
} else if constexpr (PREDICATE<std::tuple_element_t<N, TUPLE>>::value()) {
return N;
} else {
return SearchTypeListTemplate<N + 1, PREDICATE, REST...>::value();
return SearchTypeListHelper<N + 1, PREDICATE, TUPLE>::value();
}
}
};
template<template<typename> class PREDICATE, typename... TYPES>
constexpr int SearchTypeList{
SearchTypeListTemplate<0, PREDICATE, TYPES...>::value()};
SearchTypeListHelper<0, PREDICATE, std::tuple<TYPES...>>::value()};
// TypeIndex<A, TYPES...> 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<MatchType<A>::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<template<typename> class PREDICATE, typename V>
struct SearchVariantTypeTemplate;
template<template<typename> class PREDICATE, typename... Ts>
struct SearchVariantTypeTemplate<PREDICATE, std::variant<Ts...>> {
static constexpr int index{SearchTypeList<PREDICATE, Ts...>};
// to match the std::variant type with a partial specialization. And it
// works with tuples, too, of course.
template<template<typename...> class, typename> struct OverMembersHelper;
template<template<typename...> class T, typename... Ts>
struct OverMembersHelper<T, std::variant<Ts...>> {
using type = T<Ts...>;
};
template<template<typename...> class T, typename... Ts>
struct OverMembersHelper<T, std::tuple<Ts...>> {
using type = T<Ts...>;
};
template<template<typename> class PREDICATE, typename VARIANT>
constexpr int SearchVariantType{
SearchVariantTypeTemplate<PREDICATE, VARIANT>::index};
template<template<typename...> class T, typename TorV>
using OverMembers = typename OverMembersHelper<T, TorV>::type;
template<template<typename> class PREDICATE> struct SearchMembersHelper {
template<typename... Ts> struct Scanner {
static constexpr int value() { return SearchTypeList<PREDICATE, Ts...>; }
};
};
template<template<typename> class PREDICATE, typename TorV>
constexpr int SearchMembers{
OverMembers<SearchMembersHelper<PREDICATE>::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<typename... TUPLES>
using CombineTuples = typename CombineTuplesHelper<TUPLES...>::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<typename> struct VariantToTupleHelper;
template<typename... Ts> struct VariantToTupleHelper<std::variant<Ts...>> {
using type = std::tuple<Ts...>;
@ -114,5 +128,23 @@ template<typename... VARIANTS> struct CombineVariantsHelper {
template<typename... VARIANTS>
using CombineVariants = typename CombineVariantsHelper<VARIANTS...>::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<template<typename> class, template<typename...> class, typename...>
struct MapTemplateHelper;
template<template<typename> class F, template<typename...> class TorV,
typename... Ts>
struct MapTemplateHelper<F, TorV, std::tuple<Ts...>> {
using type = TorV<F<Ts>...>;
};
template<template<typename> class F, template<typename...> class TorV,
typename... Ts>
struct MapTemplateHelper<F, TorV, std::variant<Ts...>> {
using type = TorV<F<Ts>...>;
};
template<template<typename> class F, template<typename...> class TorV,
typename TV>
using MapTemplate = typename MapTemplateHelper<F, TorV, TV>::type;
} // namespace Fortran::common
#endif // FORTRAN_COMMON_TEMPLATE_H_

View File

@ -191,7 +191,7 @@ auto Expr<SomeType>::Fold(FoldingContext &context)
},
[&](auto &x) -> std::optional<Scalar<Result>> {
if (auto c{x.Fold(context)}) {
return {Scalar<Result>{std::move(*c)}};
return {common::MoveVariant<Scalar<Result>>(std::move(c->u))};
}
return std::nullopt;
}},
@ -229,7 +229,7 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context,
using Ty = TypeOf<std::decay_t<decltype(x)>>;
return Convert<Result, Ty>::FoldScalar(context, x);
},
c.u.u);
c.u);
} else if constexpr (Result::category == TypeCategory::Integer) {
if constexpr (Operand::category == TypeCategory::Integer) {
auto converted{Scalar<Result>::ConvertSigned(c)};
@ -398,7 +398,7 @@ auto RealToIntPower<A, B>::FoldScalar(FoldingContext &context,
RealFlagWarnings(context, power.flags, "raising to INTEGER power");
return {std::move(power.value)};
},
y.u.u);
y.u);
}
template<typename A>
@ -543,9 +543,8 @@ std::ostream &Expr<SomeKind<CAT>>::Dump(std::ostream &o) const {
return DumpExpr(o, u.u);
}
template<TypeCategory CAT>
std::ostream &Relational<SomeKind<CAT>>::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<SomeType>::Dump(std::ostream &o) const {
@ -669,7 +668,7 @@ auto Expr<SomeType>::ScalarValue() const -> std::optional<Scalar<Result>> {
},
[](const auto &x) -> std::optional<Scalar<Result>> {
if (auto c{x.ScalarValue()}) {
return {Scalar<Result>{std::move(*c)}};
return {common::MoveVariant<Scalar<Result>>(std::move(c->u))};
}
return std::nullopt;
}},

View File

@ -497,22 +497,16 @@ struct Relational : public Operation<Relational<A>, LogicalResult, A, A> {
// A generic relation between two operands of the same kind in some intrinsic
// type category (except LOGICAL).
template<TypeCategory CAT> struct Relational<SomeKind<CAT>> {
static constexpr TypeCategory category{CAT};
struct AnyRelational {
using Result = LogicalResult;
using Operand = SomeKind<CAT>;
template<TypeCategory C, int K> using KindRelational = Relational<Type<C, K>>;
CLASS_BOILERPLATE(Relational)
template<int KIND>
Relational(const KindRelational<category, KIND> &x) : u{x} {}
template<int KIND>
Relational(KindRelational<category, KIND> &&x) : u{std::move(x)} {}
template<typename A> AnyRelational(const A &x) : u{x} {}
template<typename A>
AnyRelational(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
std::optional<Scalar<Result>> Fold(FoldingContext &);
std::ostream &Dump(std::ostream &) const;
CategoryUnion<CAT, KindRelational> u;
common::MapTemplate<Relational, std::variant, RelationalTypes> u;
};
template<int KIND> class Expr<Type<TypeCategory::Logical, KIND>> {
@ -544,11 +538,7 @@ private:
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>,
// TODO Parentheses<Result>,
Not<KIND>, LogicalOperation<KIND>,
Relational<SomeKind<TypeCategory::Integer>>,
Relational<SomeKind<TypeCategory::Real>>,
Relational<SomeKind<TypeCategory::Complex>>,
Relational<SomeKind<TypeCategory::Character>>>
Not<KIND>, LogicalOperation<KIND>, AnyRelational>
u_;
};

View File

@ -67,7 +67,10 @@ ConvertRealOperandsResult ConvertRealOperands(
Expr<SomeType> GenericScalarToExpr(const Scalar<SomeType> &x) {
return std::visit(
[&](const auto &c) { return ToGenericExpr(SomeKindScalarToExpr(c)); },
[](const auto &c) -> Expr<SomeType> {
using Ty = TypeOf<decltype(c)>;
return {Expr<SomeKind<Ty::category>>{Expr<Ty>{c}}};
},
x.u);
}

View File

@ -141,13 +141,6 @@ Expr<SomeKind<CAT>> ToSomeKindExpr(Expr<Type<CAT, KIND>> &&x) {
return {std::move(x)};
}
template<TypeCategory CAT>
Expr<SomeKind<CAT>> SomeKindScalarToExpr(const SomeKindScalar<CAT> &x) {
return std::visit(
[](const auto &c) { return ToSomeKindExpr(ScalarConstantToExpr(c)); },
x.u.u);
}
Expr<SomeType> GenericScalarToExpr(const Scalar<SomeType> &);
template<TypeCategory CAT, int KIND>

View File

@ -112,6 +112,7 @@ struct Type<TypeCategory::Logical, KIND>
template<typename T> using Scalar = typename std::decay_t<T>::Scalar;
// Given a specific type, find the type of the same kind in another category.
template<TypeCategory C, typename T>
using SameKind = Type<C, std::decay_t<T>::kind>;
@ -194,103 +195,101 @@ struct IntrinsicTypeUnionTemplate {
template<template<TypeCategory, int> class A>
using IntrinsicTypeUnion = typename IntrinsicTypeUnionTemplate<A>::type;
// For an intrinsic type category CAT, CategoryTypes<CAT> is an instantiation
// of std::tuple<Type<CAT, K>> for every supported kind K in that category.
template<TypeCategory CAT, int... KINDS>
using CategoryTypesTuple = std::tuple<Type<CAT, KINDS>...>;
template<TypeCategory CAT> struct CategoryTypesHelper;
template<> struct CategoryTypesHelper<TypeCategory::Integer> {
using type = CategoryTypesTuple<TypeCategory::Integer, 1, 2, 4, 8, 16>;
};
template<> struct CategoryTypesHelper<TypeCategory::Real> {
using type = CategoryTypesTuple<TypeCategory::Real, 2, 4, 8, 10, 16>;
};
template<> struct CategoryTypesHelper<TypeCategory::Complex> {
using type = CategoryTypesTuple<TypeCategory::Complex, 2, 4, 8, 10, 16>;
};
template<> struct CategoryTypesHelper<TypeCategory::Character> {
using type = CategoryTypesTuple<TypeCategory::Character, 1>; // TODO: 2 & 4
};
template<> struct CategoryTypesHelper<TypeCategory::Logical> {
using type = CategoryTypesTuple<TypeCategory::Logical, 1, 2, 4, 8>;
};
template<TypeCategory CAT>
using CategoryTypes = typename CategoryTypesHelper<CAT>::type;
using NumericTypes = common::CombineTuples<CategoryTypes<TypeCategory::Integer>,
CategoryTypes<TypeCategory::Real>, CategoryTypes<TypeCategory::Complex>>;
using RelationalTypes =
common::CombineTuples<NumericTypes, CategoryTypes<TypeCategory::Character>>;
using AllIntrinsicTypes = common::CombineTuples<RelationalTypes,
CategoryTypes<TypeCategory::Logical>>;
// When Scalar<T> is S, then TypeOf<S> is T.
// TypeOf is implemented by scanning all supported types for a match
// with Type<T>::Scalar.
template<typename CONST> struct TypeOfTemplate {
template<typename A>
struct InnerPredicate { // A is a specific Type<CAT,KIND>
template<typename CONST> struct TypeOfHelper {
template<typename T> struct Predicate {
static constexpr bool value() {
return std::is_same_v<std::decay_t<CONST>,
std::decay_t<typename A::Scalar>>;
std::decay_t<typename T::Scalar>>;
}
};
template<typename A>
struct OuterPredicate { // A is a CategoryUnion<CAT, Type>
static constexpr bool value() {
return common::SearchVariantType<InnerPredicate, typename A::Variant> >=
0;
}
};
using BareTypes = IntrinsicTypeUnion<Type>;
static constexpr int CatIndex{
common::SearchVariantType<OuterPredicate, typename BareTypes::Variant>};
static_assert(
CatIndex >= 0 || !"no category found for type of scalar constant");
static constexpr TypeCategory category{BareTypes::IndexToKind(CatIndex)};
using CatType = BareTypes::template KindType<category>;
static constexpr int KindIndex{
common::SearchVariantType<InnerPredicate, typename CatType::Variant>};
static_assert(KindIndex >= 0 || !"search over category failed when repeated");
static constexpr int kind{CatType::IndexToKind(KindIndex)};
using type = Type<category, kind>;
static constexpr int index{
common::SearchMembers<Predicate, AllIntrinsicTypes>};
static_assert(index >= 0 || !"No intrinsic type found for constant type");
using type = std::tuple_element_t<index, AllIntrinsicTypes>;
};
template<typename CONST> using TypeOf = typename TypeOfTemplate<CONST>::type;
template<typename CONST> using TypeOf = typename TypeOfHelper<CONST>::type;
// Holds a scalar value of any kind within a particular intrinsic type
// category.
template<TypeCategory CAT> 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<typename TYPES> struct SomeScalar {
using Types = TYPES;
CLASS_BOILERPLATE(SomeScalar)
template<typename A> SomeKindScalar(const A &x) : u{x} {}
template<typename A> SomeScalar(const A &x) : u{x} {}
template<typename A>
SomeKindScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
SomeScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
std::optional<std::int64_t> 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<std::int64_t> {
if constexpr (TypeOf<decltype(x)>::category ==
TypeCategory::Integer) {
return {x.ToInt64()};
} else {
return std::nullopt;
}
},
u);
}
std::optional<std::string> ToString() const {
return common::GetIf<std::string>(u.u);
auto ToString() const {
return std::visit(
[](const auto &x) -> std::optional<std::string> {
if constexpr (std::is_same_v<std::string,
std::decay_t<decltype(x)>>) {
return {x};
} else {
return std::nullopt;
}
},
u);
}
template<TypeCategory C, int K> using KindScalar = Scalar<Type<C, K>>;
CategoryUnion<CAT, KindScalar> u;
template<typename T> auto GetIf() const {
return common::GetIf<Scalar<T>>(u);
}
common::MapTemplate<Scalar, std::variant, Types> u;
};
// Holds a scalar constant of any intrinsic category and size.
struct GenericScalar {
CLASS_BOILERPLATE(GenericScalar)
template<TypeCategory CAT, int KIND>
GenericScalar(const Scalar<Type<CAT, KIND>> &x) : u{SomeKindScalar<CAT>{x}} {}
template<TypeCategory CAT, int KIND>
GenericScalar(Scalar<Type<CAT, KIND>> &&x)
: u{SomeKindScalar<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::optional<std::int64_t> ToInt64() const {
if (const auto *j{std::get_if<SomeKindScalar<TypeCategory::Integer>>(&u)}) {
return j->ToInt64();
}
return std::nullopt;
}
std::optional<std::string> ToString() const {
if (const auto *c{
std::get_if<SomeKindScalar<TypeCategory::Character>>(&u)}) {
return c->ToString();
}
return std::nullopt;
}
std::variant<SomeKindScalar<TypeCategory::Integer>,
SomeKindScalar<TypeCategory::Real>, SomeKindScalar<TypeCategory::Complex>,
SomeKindScalar<TypeCategory::Character>,
SomeKindScalar<TypeCategory::Logical>>
u;
};
template<TypeCategory CAT>
using SomeKindScalar = SomeScalar<CategoryTypes<CAT>>;
using GenericScalar = SomeScalar<AllIntrinsicTypes>;
// Represents a type of any supported kind within a particular category.
template<TypeCategory CAT> struct SomeKind {
@ -304,7 +303,7 @@ using SomeComplex = SomeKind<TypeCategory::Complex>;
using SomeCharacter = SomeKind<TypeCategory::Character>;
using SomeLogical = SomeKind<TypeCategory::Logical>;
// Represents a completely generic type.
// Represents a completely generic intrinsic type.
struct SomeType {
using Scalar = GenericScalar;
};