From ab71bd343ca9afb3a278f30887c860c9c9768865 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Mon, 28 Jan 2019 16:56:50 -0800 Subject: [PATCH] [flang] folding array constructors Original-commit: flang-compiler/f18@a4e045fc5a913c7c3814820bf662205cc7687f1e Reviewed-on: https://github.com/flang-compiler/f18/pull/271 Tree-same-pre-rewrite: false --- flang/lib/evaluate/common.h | 10 ++-- flang/lib/evaluate/fold.cc | 97 ++++++++++++++++++++++++++++++++++++ flang/lib/semantics/resolve-names.cc | 35 ++++++------- 3 files changed, 118 insertions(+), 24 deletions(-) diff --git a/flang/lib/evaluate/common.h b/flang/lib/evaluate/common.h index 67268bc..aed918f 100644 --- a/flang/lib/evaluate/common.h +++ b/flang/lib/evaluate/common.h @@ -22,6 +22,7 @@ #include "../parser/char-block.h" #include "../parser/message.h" #include +#include namespace Fortran::semantics { class DerivedTypeSpec; @@ -199,19 +200,20 @@ struct FoldingContext { : messages{m}, rounding{round}, flushSubnormalsToZero{flush} {} FoldingContext(const FoldingContext &that) : messages{that.messages}, rounding{that.rounding}, - flushSubnormalsToZero{that.flushSubnormalsToZero}, pdtInstance{ - that.pdtInstance} {} + flushDenormalsToZero{that.flushDenormalsToZero}, + pdtInstance{that.pdtInstance}, impliedDos{that.impliedDos} {} FoldingContext( const FoldingContext &that, const parser::ContextualMessages &m) : messages{m}, rounding{that.rounding}, - flushSubnormalsToZero{that.flushSubnormalsToZero}, pdtInstance{ - that.pdtInstance} {} + flushDenormalsToZero{that.flushDenormalsToZero}, + pdtInstance{that.pdtInstance}, impliedDos{that.impliedDos} {} parser::ContextualMessages messages; Rounding rounding{defaultRounding}; bool flushSubnormalsToZero{false}; bool bigEndian{false}; const semantics::DerivedTypeSpec *pdtInstance{nullptr}; + std::map impliedDos; }; void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op); diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index 32e9fe8..bfc6114 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -14,6 +14,7 @@ #include "fold.h" #include "common.h" +#include "constant.h" #include "expression.h" #include "int-power.h" #include "tools.h" @@ -54,6 +55,8 @@ template Expr FoldOperation(FoldingContext &, Designator &&); template Expr> FoldOperation( FoldingContext &, TypeParamInquiry &&); +template +Expr FoldOperation(FoldingContext &, ArrayConstructor &&); // Overloads, instantiations, and specializations of FoldOperation(). @@ -209,6 +212,100 @@ Expr FoldOperation(FoldingContext &context, Designator &&designator) { std::move(designator.u)); } +// Array constructor folding + +Expr FoldOperation( + FoldingContext &context, ImpliedDoIndex &&iDo) { + auto iter{context.impliedDos.find(iDo.name)}; + CHECK(iter != context.impliedDos.end()); + return Expr{iter->second}; +} + +template class ArrayConstructorFolder { +public: + explicit ArrayConstructorFolder(const FoldingContext &c) : context_{c} { + context_.impliedDos.clear(); + } + Expr FoldArray(ArrayConstructor &&array) { + if (FoldArray(array.values)) { + std::int64_t n = elements_.size(); + return Expr{ + Constant{std::move(elements_), std::vector{n}}}; + } else { + return Expr{std::move(array)}; + } + } + +private: + bool FoldArray(const CopyableIndirection> &expr) { + Expr folded{Fold(context_, Expr{*expr})}; + if (auto *c{UnwrapExpr>(folded)}) { + // Copy elements in Fortran array element order + std::vector shape{c->shape()}; + int rank{c->Rank()}; + std::vector index(shape.size(), 1); + for (std::size_t n{c->size()}; n-- > 0;) { + elements_.push_back(c->At(index)); + for (int d{0}; d < rank && ++index[d] <= shape[d]; ++d) { + index[d] = 1; + } + } + return true; + } else { + return false; + } + } + bool FoldArray(const ImpliedDo &iDo) { + Expr lower{ + Fold(context_, Expr{*iDo.lower})}; + Expr upper{ + Fold(context_, Expr{*iDo.upper})}; + Expr stride{ + Fold(context_, Expr{*iDo.stride})}; + std::optional start{ToInt64(lower)}, end{ToInt64(upper)}, + step{ToInt64(stride)}; + if (start.has_value() && end.has_value() && step.has_value()) { + auto pair{context_.impliedDos.insert( + std::make_pair(iDo.controlVariableName, *start))}; + CHECK(pair.second); + bool result{true}; + for (std::int64_t &j{pair.first->second}; j <= *end; j += *step) { + result &= FoldArray(*iDo.values); + } + context_.impliedDos.erase(pair.first); + return result; + } else { + return false; + } + } + bool FoldArray(const ArrayConstructorValue &x) { + return std::visit([&](const auto &y) { return FoldArray(y); }, x.u); + } + bool FoldArray(const ArrayConstructorValues &xs) { + for (const auto &x : xs.values) { + if (!FoldArray(x)) { + return false; + } + } + return true; + } + + FoldingContext context_; + std::vector> elements_; +}; + +template +Expr FoldOperation(FoldingContext &context, ArrayConstructor &&array) { + ArrayConstructorFolder folder{context}; + return folder.FoldArray(std::move(array)); +} + +Expr FoldOperation( + FoldingContext &context, ArrayConstructor &&array) { + // TODO pmk: derived type array constructor folding (no Scalar to use) + return Expr{std::move(array)}; +} + // Substitute a bare type parameter reference with its value if it has one now template Expr> FoldOperation( diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index 4cd025c..f21e194 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -694,7 +694,8 @@ protected: // Declare a statement entity (e.g., an implied DO loop index). // If there isn't a type specified, implicit rules apply. // Return pointer to the new symbol, or nullptr on error. - Symbol *DeclareStatementEntity(const parser::Name &); + Symbol *DeclareStatementEntity( + const parser::Name &, const std::optional &); bool CheckUseError(const parser::Name &); void CheckAccessibility(const parser::Name &, bool, const Symbol &); @@ -3003,7 +3004,8 @@ Symbol *DeclarationVisitor::DeclareConstructEntity(const parser::Name &name) { return &symbol; } -Symbol *DeclarationVisitor::DeclareStatementEntity(const parser::Name &name) { +Symbol *DeclarationVisitor::DeclareStatementEntity(const parser::Name &name, + const std::optional &type) { if (auto *prev{FindSymbol(name)}) { if (prev->owner() == currScope()) { SayAlreadyDeclared(name, *prev); @@ -3013,8 +3015,15 @@ Symbol *DeclarationVisitor::DeclareStatementEntity(const parser::Name &name) { } Symbol &symbol{DeclareEntity(name, {})}; if (symbol.has()) { - if (auto *type{GetDeclTypeSpec()}) { - SetType(name, *type); + const DeclTypeSpec *declTypeSpec{nullptr}; + if (type.has_value()) { + BeginDeclTypeSpec(); + DeclarationVisitor::Post(*type); + declTypeSpec = GetDeclTypeSpec(); + EndDeclTypeSpec(); + } + if (declTypeSpec != nullptr) { + SetType(name, *declTypeSpec); } else { ApplyImplicitRules(symbol); } @@ -3229,16 +3238,9 @@ bool ConstructVisitor::Pre(const parser::AcImpliedDo &x) { auto &control{std::get(x.t)}; auto &type{std::get>(control.t)}; auto &bounds{std::get>(control.t)}; - if (type) { - BeginDeclTypeSpec(); - DeclarationVisitor::Post(*type); - } - if (auto *symbol{DeclareStatementEntity(bounds.name.thing.thing)}) { + if (auto *symbol{DeclareStatementEntity(bounds.name.thing.thing, type)}) { CheckScalarIntegerType(*symbol); } - if (type) { - EndDeclTypeSpec(); - } Walk(bounds); Walk(values); return false; @@ -3249,16 +3251,9 @@ bool ConstructVisitor::Pre(const parser::DataImpliedDo &x) { auto &type{std::get>(x.t)}; auto &bounds{ std::get>(x.t)}; - if (type) { - BeginDeclTypeSpec(); - DeclarationVisitor::Post(*type); - } - if (auto *symbol{DeclareStatementEntity(bounds.name.thing.thing)}) { + if (auto *symbol{DeclareStatementEntity(bounds.name.thing.thing, type)}) { CheckScalarIntegerType(*symbol); } - if (type) { - EndDeclTypeSpec(); - } Walk(bounds); Walk(objects); return false; -- 2.7.4