From e8709a4d6a9b84c7b69143a39e06a07a7b80835d Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 7 Feb 2019 12:05:27 -0800 Subject: [PATCH] [flang] checkpoint Constant based on StructureConstructor Original-commit: flang-compiler/f18@47986f0c7e1c5e47ac1aa0830c08e1dafe186fd8 Reviewed-on: https://github.com/flang-compiler/f18/pull/287 Tree-same-pre-rewrite: false --- flang/lib/evaluate/common.h | 4 -- flang/lib/evaluate/constant.cc | 18 +++++++-- flang/lib/evaluate/constant.h | 85 ++++++++++++++++++++++++++++++---------- flang/lib/evaluate/expression.cc | 2 +- flang/lib/evaluate/expression.h | 39 ++++++++++++++++-- flang/lib/evaluate/fold.cc | 47 ++++++++++++++++++---- flang/lib/evaluate/type.cc | 67 ++++++++++++++++++++++++++++++- flang/lib/evaluate/type.h | 51 +++++++++++++----------- 8 files changed, 249 insertions(+), 64 deletions(-) diff --git a/flang/lib/evaluate/common.h b/flang/lib/evaluate/common.h index d63e0cd..bd42d17 100644 --- a/flang/lib/evaluate/common.h +++ b/flang/lib/evaluate/common.h @@ -29,10 +29,6 @@ namespace Fortran::semantics { class DerivedTypeSpec; } -namespace Fortran::semantics { -class DerivedTypeSpec; -} - namespace Fortran::evaluate { using common::RelationalOperator; diff --git a/flang/lib/evaluate/constant.cc b/flang/lib/evaluate/constant.cc index 3350649..3772aa7 100644 --- a/flang/lib/evaluate/constant.cc +++ b/flang/lib/evaluate/constant.cc @@ -13,12 +13,16 @@ // limitations under the License. #include "constant.h" +#include "expression.h" #include "type.h" #include "../parser/characters.h" namespace Fortran::evaluate { + +template ConstantBase::~ConstantBase() {} + template -std::ostream &Constant::AsFortran(std::ostream &o) const { +std::ostream &ConstantBase::AsFortran(std::ostream &o) const { if (Rank() > 1) { o << "reshape("; } @@ -47,7 +51,7 @@ std::ostream &Constant::AsFortran(std::ostream &o) const { } o << '_' << Result::kind; } else { - value.u.AsFortran(o); + value.AsFortran(o); } } if (Rank() > 0) { @@ -66,7 +70,8 @@ std::ostream &Constant::AsFortran(std::ostream &o) const { } template -auto Constant::At(const std::vector &index) const -> Value { +auto ConstantBase::At(const std::vector &index) const + -> Value { CHECK(index.size() == static_cast(Rank())); std::int64_t stride{1}, offset{0}; int dim{0}; @@ -79,7 +84,7 @@ auto Constant::At(const std::vector &index) const -> Value { return values_.at(offset); } -template Constant Constant::SHAPE() const { +template Constant ConstantBase::SHAPE() const { using IntType = Scalar; std::vector result; for (std::int64_t dim : shape_) { @@ -88,5 +93,10 @@ template Constant Constant::SHAPE() const { return {std::move(result), std::vector{Rank()}}; } +Constant::Constant(const semantics::DerivedTypeSpec &spec, + std::vector &&x, std::vector &&s) + : Base{std::move(x), std::move(s)}, spec_{&spec} {} + +FOR_EACH_SPECIFIC_TYPE(template class ConstantBase) FOR_EACH_INTRINSIC_KIND(template class Constant) } diff --git a/flang/lib/evaluate/constant.h b/flang/lib/evaluate/constant.h index 5c73f96..a3983c4 100644 --- a/flang/lib/evaluate/constant.h +++ b/flang/lib/evaluate/constant.h @@ -24,24 +24,24 @@ namespace Fortran::evaluate { // N.B. Generic constants are represented by generic expressions // (like Expr & Expr) wrapping the appropriate // instantiations of Constant. -template class Constant { - static_assert(std::is_same_v || IsSpecificIntrinsicType); +template class Constant; + +template class ConstantBase { public: - using Result = T; + using Result = RESULT; using Value = Scalar; - CLASS_BOILERPLATE(Constant) - template Constant(const A &x) : values_{x} {} + template ConstantBase(const A &x) : values_{x} {} template - Constant(std::enable_if_t, A> &&x) + ConstantBase(std::enable_if_t, A> &&x) : values_{std::move(x)} {} - Constant(std::vector &&x, std::vector &&s) + ConstantBase(std::vector &&x, std::vector &&s) : values_(std::move(x)), shape_(std::move(s)) {} + ~ConstantBase(); - constexpr DynamicType GetType() const { return Result::GetType(); } int Rank() const { return static_cast(shape_.size()); } - bool operator==(const Constant &that) const { + bool operator==(const ConstantBase &that) const { return shape_ == that.shape_ && values_ == that.values_; } bool empty() const { return values_.empty(); } @@ -59,25 +59,68 @@ public: Constant SHAPE() const; std::ostream &AsFortran(std::ostream &) const; -private: +protected: std::vector values_; std::vector shape_; - // TODO pmk: make CHARACTER values contiguous (they're strings now) + +private: + const Constant &AsConstant() const { + return *static_cast *>(this); + } + + DynamicType GetType() const { return AsConstant().GetType(); } +}; + +template class Constant : public ConstantBase { +public: + using Result = T; + using ConstantBase::ConstantBase; + CLASS_BOILERPLATE(Constant) + static constexpr DynamicType GetType() { return Result::GetType(); } }; -// Would prefer to have this be a member function of Constant enabled -// only for CHARACTER, but std::enable_if<> isn't effective in that context. template -std::int64_t ConstantLEN( - const Constant> &c) { - if (c.empty()) { - return 0; - } else { - std::vector ones(c.Rank(), 1); - return c.At(ones).size(); +class Constant> + : public ConstantBase> { +public: + using Result = Type; + using ConstantBase::ConstantBase; + CLASS_BOILERPLATE(Constant) + static constexpr DynamicType GetType() { return Result::GetType(); } + std::int64_t LEN() const { + if (this->values_.empty()) { + return 0; + } else { + return static_cast(this->values_.front().size()); + } } -} + // TODO pmk: make CHARACTER values contiguous (they're strings now) +}; + +template<> class Constant : public ConstantBase { +public: + using Result = SomeDerived; + using Base = ConstantBase; + template + Constant(const semantics::DerivedTypeSpec &spec, const A &x) + : Base{x}, spec_{&spec} {} + template + Constant(const semantics::DerivedTypeSpec &spec, + std::enable_if_t, A> &&x) + : Base{std::move(x)}, spec_{&spec} {} + Constant(const semantics::DerivedTypeSpec &, std::vector &&, + std::vector &&); + + CLASS_BOILERPLATE(Constant) + DynamicType GetType() const { + return DynamicType{TypeCategory::Derived, 0, spec_}; + } + +private: + const semantics::DerivedTypeSpec *spec_; +}; +FOR_EACH_SPECIFIC_TYPE(extern template class ConstantBase) FOR_EACH_INTRINSIC_KIND(extern template class Constant) } #endif // FORTRAN_EVALUATE_CONSTANT_H_ diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 114250c..5123bca 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -150,7 +150,7 @@ Expr Expr>::LEN() const { return std::visit( common::visitors{ [](const Constant &c) { - return AsExpr(Constant{ConstantLEN(c)}); + return AsExpr(Constant{c.LEN()}); }, [](const ArrayConstructor &a) { return a.LEN(); }, [](const Parentheses &x) { return x.left().LEN(); }, diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index b52f8b3..af606e75 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -633,14 +633,47 @@ public: FOR_EACH_LOGICAL_KIND(extern template class Expr) +class StructureConstructor { +public: + using Values = std::list>>>; + + // N.B. CLASS_BOILERPLATE() can't be used here due to forward reference + // to Expr preventing the use of "= default" constructors and + // assignment operators. + StructureConstructor() = delete; + explicit StructureConstructor(const semantics::DerivedTypeSpec &spec) + : derivedTypeSpec_{&spec} {} + StructureConstructor(const StructureConstructor &); + StructureConstructor(StructureConstructor &&); + ~StructureConstructor(); + StructureConstructor &operator=(const StructureConstructor &); + StructureConstructor &operator=(StructureConstructor &&); + + const semantics::DerivedTypeSpec &derivedTypeSpec() const { + return *derivedTypeSpec_; + } + Values &values() { return values_; } + const Values &values() const { return values_; } + bool operator==(const StructureConstructor &) const; + + StructureConstructor &Add(const semantics::Symbol &, Expr &&); + int Rank() const { return 0; } + DynamicType GetType() const; + std::ostream &AsFortran(std::ostream &) const; + +private: + const semantics::DerivedTypeSpec *derivedTypeSpec_; + Values values_; +}; + // An expression whose result has a derived type. template<> class Expr : public ExpressionBase { public: using Result = SomeDerived; EVALUATE_UNION_CLASS_BOILERPLATE(Expr) - // TODO: structure constructor - std::variant, ArrayConstructor, - FunctionRef> + std::variant, ArrayConstructor, StructureConstructor, + Designator, FunctionRef> u; }; diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index d24e07e..cd5a9ba 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -57,6 +57,7 @@ Expr> FoldOperation( FoldingContext &, TypeParamInquiry &&); template Expr FoldOperation(FoldingContext &, ArrayConstructor &&); +Expr FoldOperation(FoldingContext &, StructureConstructor &&); // Overloads, instantiations, and specializations of FoldOperation(). @@ -230,9 +231,13 @@ public: Expr FoldArray(ArrayConstructor &&array) { if (FoldArray(array.values)) { std::int64_t n = elements_.size(); - Expr result{ - Constant{std::move(elements_), std::vector{n}}}; - return result; + if constexpr (std::is_same_v) { + return Expr{Constant{array.type.spec(), std::move(elements_), + std::vector{n}}}; + } else { + return Expr{ + Constant{std::move(elements_), std::vector{n}}}; + } } else { return Expr{std::move(array)}; } @@ -304,11 +309,14 @@ Expr FoldOperation(FoldingContext &context, ArrayConstructor &&array) { return result; } -// TODO this specialization is a placeholder: don't fold array constructors -// of derived type for now Expr FoldOperation( - FoldingContext &context, ArrayConstructor &&array) { - return Expr{std::move(array)}; + FoldingContext &context, StructureConstructor &&structure) { + StructureConstructor result{structure.derivedTypeSpec()}; + for (auto &&[symbol, value] : std::move(structure.values())) { + result.Add(*symbol, Fold(context, std::move(*value))); + } + return Expr{ + Constant{result.derivedTypeSpec(), result}}; } // Substitute a bare type parameter reference with its value if it has one now @@ -783,6 +791,8 @@ template bool IsConstExpr(ConstExprContext &, const ArrayConstructorValues &); template bool IsConstExpr(ConstExprContext &, const ArrayConstructor &); +bool IsConstExpr(ConstExprContext &, const semantics::DerivedTypeSpec &); +bool IsConstExpr(ConstExprContext &, const StructureConstructor &); bool IsConstExpr(ConstExprContext &, const BaseObject &); bool IsConstExpr(ConstExprContext &, const Component &); bool IsConstExpr(ConstExprContext &, const Triplet &); @@ -843,6 +853,29 @@ template bool IsConstExpr(ConstExprContext &context, const ArrayConstructor &array) { return IsConstExpr(context, array.values); } +bool IsConstExpr( + ConstExprContext &context, const semantics::DerivedTypeSpec &spec) { + for (const auto &nameValue : spec.parameters()) { + const auto &value{nameValue.second}; + if (!value.isExplicit() || !value.GetExplicit().has_value() || + !IsConstExpr(context, *value.GetExplicit())) { + return false; + } + } + return true; +} +bool IsConstExpr( + ConstExprContext &context, const StructureConstructor &structure) { + if (!IsConstExpr(context, structure.derivedTypeSpec())) { + return false; + } + for (const auto &symbolExpr : structure.values()) { + if (!IsConstExpr(context, symbolExpr.second)) { + return false; + } + } + return true; +} bool IsConstExpr(ConstExprContext &context, const BaseObject &base) { return IsConstExpr(context, base.u); } diff --git a/flang/lib/evaluate/type.cc b/flang/lib/evaluate/type.cc index ee45eb1..1a521d4 100644 --- a/flang/lib/evaluate/type.cc +++ b/flang/lib/evaluate/type.cc @@ -13,6 +13,7 @@ // limitations under the License. #include "type.h" +#include "expression.h" #include "fold.h" #include "../common/idioms.h" #include "../semantics/scope.h" @@ -20,6 +21,8 @@ #include "../semantics/type.h" #include #include +#include +#include #include using namespace std::literals::string_literals; @@ -182,7 +185,69 @@ bool SomeKind::operator==( return spec_ == that.spec_ && descriptor_ == that.descriptor_; } +static std::ostream &DerivedTypeSpecAsFortran( + std::ostream &o, const semantics::DerivedTypeSpec &spec) { + o << "TYPE("s << spec.typeSymbol().name().ToString(); + if (!spec.parameters().empty()) { + char ch{'('}; + for (const auto &[name, value] : spec.parameters()) { + value.GetExplicit()->AsFortran(o << ch << name.ToString() << '='); + ch = ','; + } + o << ')'; + } + return o; +} + std::string SomeDerived::AsFortran() const { - return "TYPE("s + spec().typeSymbol().name().ToString() + ')'; + std::stringstream out; + DerivedTypeSpecAsFortran(out, spec()); + return out.str(); +} + +StructureConstructor::StructureConstructor(const StructureConstructor &that) + : derivedTypeSpec_{that.derivedTypeSpec_}, values_{that.values_} {} +StructureConstructor::StructureConstructor(StructureConstructor &&that) + : derivedTypeSpec_{that.derivedTypeSpec_}, values_{std::move(that.values_)} {} +StructureConstructor::~StructureConstructor() {} +StructureConstructor &StructureConstructor::operator=( + const StructureConstructor &that) { + derivedTypeSpec_ = that.derivedTypeSpec_; + values_ = that.values_; + return *this; +} +StructureConstructor &StructureConstructor::operator=( + StructureConstructor &&that) { + derivedTypeSpec_ = that.derivedTypeSpec_; + values_ = std::move(that.values_); + return *this; +} + +bool StructureConstructor::operator==(const StructureConstructor &that) const { + return derivedTypeSpec_ == that.derivedTypeSpec_ && values_ == that.values_; +} + +DynamicType StructureConstructor::GetType() const { + return {TypeCategory::Derived, 0, derivedTypeSpec_}; +} + +StructureConstructor &StructureConstructor::Add( + const Symbol &symbol, Expr &&expr) { + values_.emplace_back(&symbol, std::move(expr)); + return *this; +} + +std::ostream &StructureConstructor::AsFortran(std::ostream &o) const { + DerivedTypeSpecAsFortran(o, *derivedTypeSpec_); + if (values_.empty()) { + o << '('; + } else { + char ch{'('}; + for (const auto &[symbol, value] : values_) { + value->AsFortran(o << ch << symbol->name().ToString() << '='); + ch = ','; + } + } + return o << ')'; } } diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 1fc5a6a..d40a255 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace Fortran::semantics { @@ -176,8 +177,6 @@ public: // Type functions -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>; @@ -245,33 +244,22 @@ template constexpr bool IsLengthlessIntrinsicType{ common::HasMember}; -// When Scalar is S, then TypeOf is T. -// TypeOf is implemented by scanning all supported types for a match -// with Type::Scalar. -template struct TypeOfHelper { - template struct Predicate { - static constexpr bool value() { - return std::is_same_v, - std::decay_t>; - } - }; - static constexpr int index{ - common::SearchMembers}; - using type = std::conditional_t= 0, - std::tuple_element_t, void>; -}; - -template using TypeOf = typename TypeOfHelper::type; - // Represents a type of any supported kind within a particular category. template struct SomeKind { static constexpr TypeCategory category{CATEGORY}; constexpr bool operator==(const SomeKind &) const { return true; } }; +// Represents a completely generic type (but not typeless). +struct SomeType {}; + +// Represents a derived type +class StructureConstructor; + template<> class SomeKind { public: static constexpr TypeCategory category{TypeCategory::Derived}; + using Scalar = StructureConstructor; CLASS_BOILERPLATE(SomeKind) explicit SomeKind(const semantics::DerivedTypeSpec &dts, @@ -297,11 +285,28 @@ using SomeComplex = SomeKind; using SomeCharacter = SomeKind; using SomeLogical = SomeKind; using SomeDerived = SomeKind; - -// Represents a completely generic type (but not typeless). using SomeCategory = std::tuple; -struct SomeType {}; + +template using Scalar = typename std::decay_t::Scalar; + +// When Scalar is S, then TypeOf is T. +// TypeOf is implemented by scanning all supported types for a match +// with Type::Scalar. +template struct TypeOfHelper { + template struct Predicate { + static constexpr bool value() { + return std::is_same_v, + std::decay_t>; + } + }; + static constexpr int index{ + common::SearchMembers}; + using type = std::conditional_t= 0, + std::tuple_element_t, void>; +}; + +template using TypeOf = typename TypeOfHelper::type; // For generating "[extern] template class", &c. boilerplate #define EXPAND_FOR_EACH_INTEGER_KIND(M, P) \ -- 2.7.4