From 9236fa92ae958bb09efd348321888e8782dcb279 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Tue, 11 Sep 2018 17:06:44 -0700 Subject: [PATCH] [flang] array references Original-commit: flang-compiler/f18@5659510c31f858bdba91ea58de3df21bc1aac08c Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false --- flang/lib/evaluate/expression.h | 10 -- flang/lib/evaluate/tools.h | 24 +++++ flang/lib/semantics/expression.cc | 214 +++++++++++++++++++++++++++++--------- 3 files changed, 190 insertions(+), 58 deletions(-) diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index 3d9050d..b7f51ca 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -437,8 +437,6 @@ public: template Expr(const A &x) : u{x} {} template Expr(std::enable_if_t, A> &&x) : u(std::move(x)) {} - Expr(const DataRef &x) : u{DataReference{x}} {} - Expr(const FunctionRef &x) : u{FunctionReference{x}} {} private: using Conversions = std::variant, @@ -465,8 +463,6 @@ public: template Expr(const A &x) : u{x} {} template Expr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - Expr(const DataRef &x) : u{DataReference{x}} {} - Expr(const FunctionRef &x) : u{FunctionReference{x}} {} private: // N.B. Real->Complex and Complex->Real conversions are done with CMPLX @@ -495,8 +491,6 @@ public: template Expr(const A &x) : u{x} {} template Expr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - Expr(const DataRef &x) : u{DataReference{x}} {} - Expr(const FunctionRef &x) : u{FunctionReference{x}} {} // Note that many COMPLEX operations are represented as REAL operations // over their components (viz., conversions, negation, add, and subtract). @@ -538,8 +532,6 @@ public: template Expr(const A &x) : u{x} {} template Expr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - Expr(const DataRef &x) : u{DataReference{x}} {} - Expr(const FunctionRef &x) : u{FunctionReference{x}} {} template Expr(CopyableIndirection &&x) : u{std::move(x)} {} Expr LEN() const; @@ -625,8 +617,6 @@ public: template Expr(const A &x) : u(x) {} template Expr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - Expr(const DataRef &x) : u{DataReference{x}} {} - Expr(const FunctionRef &x) : u{FunctionReference{x}} {} private: using Operations = std::variant, diff --git a/flang/lib/evaluate/tools.h b/flang/lib/evaluate/tools.h index d3bf4a9..29186e4 100644 --- a/flang/lib/evaluate/tools.h +++ b/flang/lib/evaluate/tools.h @@ -389,5 +389,29 @@ Expr> operator/( return PromoteAndCombine(std::move(x), std::move(y)); } +// A utility for use with common::SearchDynamicTypes to create generic +// expressions when an intrinsic type category for (say) a variable is known +// but the kind parameter value is not. +template class TEMPLATE, typename VALUE> +struct TypeKindVisitor { + using Result = std::optional>; + static constexpr std::size_t Types{std::tuple_size_v>}; + + TypeKindVisitor(int k, VALUE &&x) : kind{k}, value{std::move(x)} {} + TypeKindVisitor(int k, const VALUE &x) : kind{k}, value{x} {} + + template Result Test() { + using Ty = std::tuple_element_t>; + if (kind == Ty::kind) { + return AsGenericExpr( + AsCategoryExpr(AsExpr(TEMPLATE{std::move(value)}))); + } + return std::nullopt; + } + + int kind; + VALUE value; +}; + } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_TOOLS_H_ diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index cb5da28..5d4eb50 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -108,6 +108,12 @@ struct ExprAnalyzer { MaybeExpr Analyze(const parser::Expr::DefinedBinary &); MaybeExpr Analyze(const parser::Call &); + std::optional> AsSubscript(MaybeExpr &&); + std::optional> TripletPart( + const std::optional &); + std::optional Analyze(const parser::SectionSubscript &); + std::vector Analyze(const std::list &); + FoldingContext &context; const semantics::IntrinsicTypeDefaultKinds &defaults; }; @@ -165,32 +171,12 @@ MaybeExpr AnalyzeHelper(ExprAnalyzer &ea, const common::Indirection &x) { return AnalyzeHelper(ea, *x); } -// A helper class used with common::SearchDynamicTypes when constructing -// a literal constant with a dynamic kind in some type category. -template struct ConstantTypeVisitor { - using Result = std::optional>>; - static constexpr std::size_t Types{std::tuple_size_v>}; - - ConstantTypeVisitor(int k, const VALUE &x) : kind{k}, value{x} {} - - template Result Test() { - using Ty = std::tuple_element_t>; - if (kind == Ty::kind) { - return {AsCategoryExpr(AsExpr(Constant{std::move(value)}))}; - } - return std::nullopt; - } - - int kind; - VALUE value; -}; - template<> MaybeExpr AnalyzeHelper( ExprAnalyzer &ea, const parser::HollerithLiteralConstant &x) { - return AsMaybeExpr(common::SearchDynamicTypes( - ConstantTypeVisitor{ - ea.defaults.defaultCharacterKind, x.v})); + return common::SearchDynamicTypes( + TypeKindVisitor{ + ea.defaults.defaultCharacterKind, x.v}); } template<> @@ -322,12 +308,12 @@ MaybeExpr IntLiteralConstant(ExprAnalyzer &ea, const PARSED &x) { ea.defaults.defaultIntegerKind)}; auto value{std::get<0>(x.t)}; // std::(u)int64_t auto result{common::SearchDynamicTypes( - ConstantTypeVisitor{ + TypeKindVisitor{ kind, static_cast(value)})}; if (!result.has_value()) { ea.context.messages.Say("unsupported INTEGER(KIND=%u)"_err_en_US, kind); } - return AsMaybeExpr(std::move(result)); + return result; } MaybeExpr ExprAnalyzer::Analyze(const parser::IntLiteralConstant &x) { @@ -437,12 +423,12 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::CharLiteralConstant &x) { int kind{Analyze(std::get>(x.t), 1)}; auto value{std::get(x.t)}; auto result{common::SearchDynamicTypes( - ConstantTypeVisitor{ + TypeKindVisitor{ kind, std::move(value)})}; if (!result.has_value()) { context.messages.Say("unsupported CHARACTER(KIND=%u)"_err_en_US, kind); } - return AsMaybeExpr(std::move(result)); + return result; } MaybeExpr ExprAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) { @@ -450,47 +436,179 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) { defaults.defaultLogicalKind)}; bool value{std::get(x.t)}; auto result{common::SearchDynamicTypes( - ConstantTypeVisitor{ + TypeKindVisitor{ kind, std::move(value)})}; if (!result.has_value()) { context.messages.Say("unsupported LOGICAL(KIND=%u)"_err_en_US, kind); } - return AsMaybeExpr(std::move(result)); + return result; +} + +template +MaybeExpr DataRefIfType( + const semantics::Symbol &symbol, int defaultKind, DataRef &&dataRef) { + if (auto *details{symbol.detailsIf()}) { + if (details->type().has_value()) { + if (details->type()->category() == + semantics::DeclTypeSpec::Category::Intrinsic) { + std::uint64_t kindParam{ + details->type()->intrinsicTypeSpec().kind().value().value()}; + int kind = static_cast(kindParam); + if (static_cast(kind) == kindParam) { + // TODO: Inspection of semantics::IntrinsicTypeSpec requires the use + // of forbidden RTTI via dynamic_cast<>. See whether + // semantics::IntrinsicTypeSpec can be augmented with query + // interfaces instead. + if (dynamic_cast( + &details->type()->intrinsicTypeSpec()) != nullptr) { + if (kind == 0) { // TODO: resolve default kinds in semantics + kind = defaultKind; + } + if (MaybeExpr result{common::SearchDynamicTypes( + TypeKindVisitor{ + kind, std::move(dataRef)})}) { + return result; + } + } + } + } + } + } + return std::nullopt; +} + +static MaybeExpr TypedDataRef(const semantics::Symbol &symbol, + const semantics::IntrinsicTypeDefaultKinds &defaults, DataRef &&dataRef) { + if (MaybeExpr result{ + DataRefIfType( + symbol, defaults.defaultIntegerKind, std::move(dataRef))}) { + return result; + } + if (MaybeExpr result{ + DataRefIfType( + symbol, defaults.defaultRealKind, std::move(dataRef))}) { + return result; + } + if (MaybeExpr result{ + DataRefIfType( + symbol, defaults.defaultRealKind, std::move(dataRef))}) { + return result; + } + if (MaybeExpr result{ + DataRefIfType( + symbol, defaults.defaultCharacterKind, std::move(dataRef))}) { + return result; + } + if (MaybeExpr result{ + DataRefIfType( + symbol, defaults.defaultLogicalKind, std::move(dataRef))}) { + return result; + } + return std::nullopt; } MaybeExpr ExprAnalyzer::Analyze(const parser::Name &n) { if (n.symbol == nullptr) { - // TODO: convert to CHECK later - context.messages.Say("name (%s) is not resolved to an object"_err_en_US, + // TODO: convert this to a CHECK later + context.messages.Say( + "TODO: name (%s) is not resolved to an object"_err_en_US, n.ToString().data()); - } else if (auto *details{ - n.symbol->detailsIf()}) { - if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) { - // TODO pmk get type and value - context.messages.Say( - "pmk: PARAMETER references not yet implemented"_err_en_US); - } else { - // TODO pmk variables - context.messages.Say( - "name (%s) is not a defined constant"_err_en_US, n.ToString().data()); - } + } else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) { + context.messages.Say( + "TODO: PARAMETER references not yet implemented"_err_en_US); // TODO: enumerators, do they have the PARAMETER attribute? } else { - // TODO: convert to CHECK later - context.messages.Say( - "name (%s) lacks details in the symbol table"_err_en_US, + if (MaybeExpr result{ + TypedDataRef(*n.symbol, defaults, DataRef{*n.symbol})}) { + return result; + } + context.messages.Say("%s is not of a supported type and kind"_err_en_US, n.ToString().data()); } - return std::nullopt; // TODO parameters and enumerators + return std::nullopt; } MaybeExpr ExprAnalyzer::Analyze(const parser::Substring &ss) { - context.messages.Say("pmk: Substring unimplemented\n"_err_en_US); + context.messages.Say("TODO: Substring unimplemented\n"_err_en_US); return std::nullopt; } +std::optional> ExprAnalyzer::AsSubscript( + MaybeExpr &&expr) { + if (expr.has_value()) { + if (auto *intExpr{std::get_if>(&expr->u)}) { + if (auto *ssIntExpr{std::get_if>(&intExpr->u)}) { + return {std::move(*ssIntExpr)}; + } + return {Expr{ + Convert{ + std::move(*intExpr)}}}; + } else { + context.messages.Say("subscript expression is not INTEGER"_err_en_US); + } + } + return std::nullopt; +} + +std::optional> ExprAnalyzer::TripletPart( + const std::optional &s) { + if (s.has_value()) { + return AsSubscript(AnalyzeHelper(*this, *s)); + } + return std::nullopt; +} + +std::optional ExprAnalyzer::Analyze( + const parser::SectionSubscript &ss) { + return std::visit( + common::visitors{[&](const parser::SubscriptTriplet &t) { + return std::make_optional( + Subscript{Triplet{TripletPart(std::get<0>(t.t)), + TripletPart(std::get<1>(t.t)), + TripletPart(std::get<2>(t.t))}}); + }, + [&](const auto &s) -> std::optional { + if (auto subscriptExpr{AsSubscript(AnalyzeHelper(*this, s))}) { + return {Subscript{std::move(*subscriptExpr)}}; + } else { + return std::nullopt; + } + }}, + ss.u); +} + +std::vector ExprAnalyzer::Analyze( + const std::list &sss) { + std::vector subscripts; + for (const auto &s : sss) { + if (auto subscript{Analyze(s)}) { + subscripts.emplace_back(std::move(*subscript)); + } + } + return subscripts; +} + MaybeExpr ExprAnalyzer::Analyze(const parser::ArrayElement &ae) { - context.messages.Say("pmk: ArrayElement unimplemented\n"_err_en_US); + std::vector subscripts{Analyze(ae.subscripts)}; + if (const parser::Name * name{std::get_if(&ae.base.u)}) { + if (name->symbol == nullptr) { + // TODO: convert this to a CHECK later + context.messages.Say( + "TODO: name (%s) is not resolved to an object"_err_en_US, + name->ToString().data()); + } else { + ArrayRef arrayRef{*name->symbol, std::move(subscripts)}; + return TypedDataRef( + *name->symbol, defaults, DataRef{std::move(arrayRef)}); + } + } else if (const auto *component{ + std::get_if>( + &ae.base.u)}) { + // pmk continue + } else { + CHECK(!"parser::ArrayRef base DataRef is neither Name nor " + "StructureComponent"); + } return std::nullopt; } -- 2.7.4