From 0aae9893a5293e4abce0f45febe1285246164655 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 19 Jul 2018 09:53:42 -0700 Subject: [PATCH] [flang] checkpoint Original-commit: flang-compiler/f18@7fae33797a4245c0be531dda27ec0fb8cddf4d37 Reviewed-on: https://github.com/flang-compiler/f18/pull/144 Tree-same-pre-rewrite: false --- flang/lib/evaluate/expression.cc | 81 +++++++++++++++++++++ flang/lib/evaluate/expression.h | 64 ++++++++++++++--- flang/lib/evaluate/type.h | 14 +++- flang/lib/parser/message.h | 4 ++ flang/lib/parser/parse-tree.h | 2 +- flang/lib/semantics/expression.cc | 115 +++++++++++++++++++++++------- flang/lib/semantics/expression.h | 27 ++++--- flang/lib/semantics/type.h | 2 +- 8 files changed, 263 insertions(+), 46 deletions(-) diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index b2d4e9036fea..f2032eca7039 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -381,6 +381,87 @@ std::optional::Constant> IntegerExpr::Fold( u_); } +template +std::optional::Constant> +RealExpr::ConstantValue() const { + if (auto c{std::get_if(&u_)}) { + return {*c}; + } + return {}; +} + +template void RealExpr::Fold(FoldingContext &context) { + // TODO +} + +template +std::optional::Constant> +ComplexExpr::ConstantValue() const { + if (auto c{std::get_if(&u_)}) { + return {*c}; + } + return {}; +} + +template void ComplexExpr::Fold(FoldingContext &context) { + // TODO +} + +template +std::optional::Constant> +CharacterExpr::ConstantValue() const { + if (auto c{std::get_if(&u_)}) { + return {*c}; + } + return {}; +} + +template void CharacterExpr::Fold(FoldingContext &context) { + // TODO +} + +std::optional LogicalExpr::ConstantValue() const { + if (auto c{std::get_if(&u_)}) { + return {*c}; + } + return {}; +} + +void LogicalExpr::Fold(FoldingContext &context) { + // TODO and comparisons too +} + +std::optional GenericExpr::ConstantValue() const { + return std::visit([](const auto &x) -> std::optional { + if (auto c{x.ConstantValue()}) { + return {GenericConstant{std::move(*c)}}; + } + return {}; + }, u); +} + +template std::optional> CategoryExpr::ConstantValue() const { + return std::visit([](const auto &x) -> std::optional> { + if (auto c{x.ConstantValue()}) { + return {CategoryConstant{std::move(*c)}}; + } + return {}; + }, u); +} + +template void CategoryExpr::Fold(FoldingContext &context) { + std::visit([&](auto &x){ x.Fold(context); }, u); +} + +void GenericExpr::Fold(FoldingContext &context) { + std::visit([&](auto &x){ x.Fold(context); }, u); +} + +template struct CategoryExpr; +template struct CategoryExpr; +template struct CategoryExpr; +template struct CategoryExpr; + template class Expr; template class Expr; template class Expr; diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index 4b333aa95d2a..947e1763dd3c 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -236,6 +236,9 @@ public: Expr(std::enable_if_t, A> &&x) : u_{std::move(x)} {} template Expr(CopyableIndirection &&x) : u_{std::move(x)} {} + std::optional ConstantValue() const; + void Fold(FoldingContext &c); + private: std::variant, CopyableIndirection, CopyableIndirection, @@ -285,6 +288,9 @@ public: Expr(std::enable_if_t, A> &&x) : u_{std::move(x)} {} template Expr(CopyableIndirection &&x) : u_{std::move(x)} {} + std::optional ConstantValue() const; + void Fold(FoldingContext &c); + private: std::variant, CopyableIndirection, Parentheses, Negate, Add, Subtract, @@ -315,6 +321,8 @@ public: Expr(std::enable_if_t, A> &&x) : u_{std::move(x)} {} template Expr(CopyableIndirection &&x) : u_{std::move(x)} {} + std::optional ConstantValue() const; + void Fold(FoldingContext &c); SubscriptIntegerExpr LEN() const; private: @@ -335,6 +343,7 @@ template struct Comparison : Binary { : Binary{a, b}, opr{r} {} Comparison(RelationalOperator r, EXPR &&a, EXPR &&b) : Binary{std::move(a), std::move(b)}, opr{r} {} + std::optional Fold(FoldingContext &c); RelationalOperator opr; }; @@ -359,11 +368,12 @@ extern template struct Comparison>; // of a specific category. template struct CategoryComparison { CLASS_BOILERPLATE(CategoryComparison) + template using KindComparison = Comparison>; template - CategoryComparison(const Comparison> &x) : u{x} {} + CategoryComparison(const KindComparison &x) : u{x} {} template - CategoryComparison(Comparison> &&x) : u{std::move(x)} {} - template using KindComparison = Comparison>; + CategoryComparison(KindComparison &&x) : u{std::move(x)} {} + std::optional Fold(FoldingContext &c); typename KindsVariant::type u; }; @@ -372,7 +382,7 @@ template<> class Expr { public: using Constant = bool; struct Not : Unary { - using Unary::Unary; + using Unary::Unary; }; using Bin = Binary; struct And : public Bin { @@ -389,7 +399,7 @@ public: }; CLASS_BOILERPLATE(Expr) - Expr(Constant x) : u_{x} {} + Expr(bool x) : u_{x} {} template Expr(const Comparison> &x) : u_{CategoryComparison{x}} {} template @@ -400,8 +410,11 @@ public: Expr(std::enable_if_t, A> &&x) : u_{std::move(x)} {} template Expr(CopyableIndirection &&x) : u_{std::move(x)} {} + std::optional ConstantValue() const; + void Fold(FoldingContext &c); + private: - std::variant, + std::variant, CopyableIndirection, Not, And, Or, Eqv, Neqv, CategoryComparison, CategoryComparison, CategoryComparison, @@ -427,17 +440,43 @@ extern template class Expr; extern template class Expr; extern template class Expr; +// Holds a constant of any kind in an intrinsic type category. +template struct CategoryConstant { + CLASS_BOILERPLATE(CategoryConstant) + template using KindConstant = typename Expr::Constant; + template CategoryConstant(const A &x) : u{x} {} + template CategoryConstant(std::enable_if_t, A> &&x) : u{std::move(x)} {} + typename KindsVariant::type u; +}; + +// Holds a constant of any intrinsic category and size. +struct GenericConstant { + CLASS_BOILERPLATE(GenericConstant) + template + GenericConstant(const typename Expr::Constant &x) : u{CategoryConstant{x}} {} + template + GenericConstant(typename Expr::Constant &&x) : u{CategoryConstant{std::move(x)}} {} + template GenericConstant(const A &x) : u{x} {} + template + GenericConstant(std::enable_if_t, A> &&x) + : u{std::move(x)} {} + std::variant, CategoryConstant, CategoryConstant, CategoryConstant, bool> u; +}; + // Dynamically polymorphic expressions that can hold any supported kind -// of a specific category. +// of a specific intrinsic type category. template struct CategoryExpr { CLASS_BOILERPLATE(CategoryExpr) - template CategoryExpr(const Expr &x) : u{x} {} - template CategoryExpr(Expr &&x) : u{std::move(x)} {} - template using KindExpr = Expr; + template using KindExpr = Expr; + template CategoryExpr(const KindExpr &x) : u{x} {} + template CategoryExpr(KindExpr &&x) : u{std::move(x)} {} + std::optional> ConstantValue() const; + void Fold(FoldingContext &); typename KindsVariant::type u; }; -// A completely generic expression, polymorphic across the type categories. +// A completely generic expression, polymorphic across the intrinsic type +// categories and each of their kinds. struct GenericExpr { CLASS_BOILERPLATE(GenericExpr) template @@ -448,6 +487,9 @@ struct GenericExpr { template GenericExpr(std::enable_if_t, A> &&x) : u{std::move(x)} {} + std::optional ConstantValue() const; + void Fold(FoldingContext &); + int Rank() const { return 1; } // TODO std::variant u; diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index f17b8918f786..809be00bd5f1 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -117,13 +117,24 @@ using DefaultCharacter = Type; using SubscriptInteger = Type; +// These macros invoke other macros on each of the supported kinds of +// a given category. +#define COMMA , +#define FOR_EACH_INTEGER_KIND(M,SEP) M(1) SEP M(2) SEP M(4) SEP M(8) SEP M(16) +#define FOR_EACH_REAL_KIND(M,SEP) M(2) SEP M(4) SEP M(8) SEP M(10) SEP M(16) +#define FOR_EACH_COMPLEX_KIND(M,SEP) FOR_EACH_REAL_KIND(M,SEP) +#define FOR_EACH_CHARACTER_KIND(M,SEP) M(1) +#define FOR_EACH_LOGICAL_KIND(M,SEP) M(1) SEP M(2) SEP M(4) SEP M(8) + // These templates create instances of std::variant<> that can contain // applications of some class template to all of the supported kinds of // a category of intrinsic type. +#define TKIND(K) T template class T> struct KindsVariant; template class T> struct KindsVariant { - using type = std::variant, T<2>, T<4>, T<8>, T<16>>; + using type = std::variant; }; +// TODO use FOR_EACH... template class T> struct KindsVariant { using type = std::variant, T<4>, T<8>, T<10>, T<16>>; }; @@ -136,5 +147,6 @@ template class T> struct KindsVariant { template class T> struct KindsVariant { using type = std::variant, T<2>, T<4>, T<8>>; }; +#undef TKIND } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_TYPE_H_ diff --git a/flang/lib/parser/message.h b/flang/lib/parser/message.h index dcc1eacf36bd..1f0c5c3122b0 100644 --- a/flang/lib/parser/message.h +++ b/flang/lib/parser/message.h @@ -113,6 +113,8 @@ public: Message(ProvenanceRange pr, const MessageFixedText &t) : location_{pr}, text_{t} {} + Message(ProvenanceRange pr, const MessageFormattedText &s) + : location_{pr}, text_{std::move(s)} {} Message(ProvenanceRange pr, MessageFormattedText &&s) : location_{pr}, text_{std::move(s)} {} Message(ProvenanceRange pr, const MessageExpectedText &t) @@ -120,6 +122,8 @@ public: Message(CharBlock csr, const MessageFixedText &t) : location_{csr}, text_{t} {} + Message(CharBlock csr, const MessageFormattedText &s) + : location_{csr}, text_{std::move(s)} {} Message(CharBlock csr, MessageFormattedText &&s) : location_{csr}, text_{std::move(s)} {} Message(CharBlock csr, const MessageExpectedText &t) diff --git a/flang/lib/parser/parse-tree.h b/flang/lib/parser/parse-tree.h index 4cf9d58d4299..a40972a1ec35 100644 --- a/flang/lib/parser/parse-tree.h +++ b/flang/lib/parser/parse-tree.h @@ -62,7 +62,7 @@ class Symbol; } // namespace Fortran::semantics namespace Fortran::evaluate { -class GenericExpr; +struct GenericExpr; } // namespace Fortran::evaluate // Most non-template classes in this file use these default definitions diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 4f58a5e4be8a..297ec280c3ec 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -19,45 +19,112 @@ using namespace Fortran::parser::literals; namespace Fortran::semantics { -std::optional ExpressionAnalyzer::Analyze( - const parser::Expr &x) { - return std::visit( - common::visitors{ - [&](const parser::LiteralConstant &c) { return Analyze(c); }, - [&](const auto &) { return std::optional{}; }}, - x.u); +template +std::optional AnalyzeHelper(ExpressionAnalyzer &ea, const A &tree) { + return ea.Analyze(tree); } -std::optional ExpressionAnalyzer::Analyze( - const parser::IntLiteralConstant &x) { - std::uint64_t kind = defaultIntegerKind_; - const auto &kindParam{std::get>(x.t)}; - if (kindParam.has_value()) { - std::visit(common::visitors{[&](std::uint64_t k) { kind = k; }, - [&](const auto &) { - messages_.Say(at_, "unimp kind param"_err_en_US); - }}, - kindParam->u); +template +std::optional AnalyzeHelper(ExpressionAnalyzer &ea, + const parser::Scalar &tree) { + std::optional result{AnalyzeHelper(ea, tree.thing)}; + if (result.has_value()) { + if (result->Rank() > 1) { + ea.Say("must be scalar"_err_en_US); + return {}; + } } + return result; +} + +template +std::optional AnalyzeHelper(ExpressionAnalyzer &ea, + const parser::Constant &tree) { + std::optional result{AnalyzeHelper(ea, tree.thing)}; + if (result.has_value()) { + result->Fold(ea.context()); + if (!result->ConstantValue().has_value()) { + ea.Say("must be constant"_err_en_US); + return {}; + } + } + return result; +} + +template +std::optional AnalyzeHelper(ExpressionAnalyzer &ea, + const parser::Integer &tree) { + std::optional result{AnalyzeHelper(ea, tree.thing)}; + if (result.has_value() && !std::holds_alternative(result->u)) { + ea.Say("must be integer"_err_en_US); + return {}; + } + return result; +} + +template<> std::optional AnalyzeHelper(ExpressionAnalyzer &ea, + const parser::Name &n) { + // TODO + return {}; +} + +ExpressionAnalyzer::KindParam +ExpressionAnalyzer::Analyze(const std::optional &kindParam, + KindParam defaultKind, KindParam kanjiKind) { + if (!kindParam.has_value()) { + return defaultKind; + } + return std::visit(common::visitors{[](std::uint64_t k) { return static_cast(k); }, + [&](const parser::Scalar>> &n) { + if (std::optional oge{AnalyzeHelper(*this, n)}) { + if (std::optional ogc{oge->ConstantValue()}) { + // TODO pmk more here next + } + } + return defaultKind; + }, + [&](parser::KindParam::Kanji) { + if (kanjiKind >= 0) { + return kanjiKind; + } + Say("Kanji not allowed here"_err_en_US); + return defaultKind; }}, kindParam->u); +} + +template<> std::optional AnalyzeHelper(ExpressionAnalyzer &ea, + const parser::IntLiteralConstant &x) { + auto kind{ea.Analyze(std::get>(x.t), + ea.defaultIntegerKind())}; std::uint64_t value{std::get(x.t)}; switch (kind) { - case 4: - return {evaluate::GenericExpr{ - evaluate::GenericIntegerExpr{evaluate::IntegerExpr<4>{value}}}}; +#define CASE(k) case k: return {evaluate::GenericExpr{evaluate::GenericIntegerExpr{evaluate::IntegerExpr{value}}}}; + FOR_EACH_INTEGER_KIND(CASE,) +#undef CASE default: - messages_.Say(at_, - parser::MessageFormattedText{ + ea.Say(parser::MessageFormattedText{ "unimplemented INTEGER kind (%ju)"_err_en_US, static_cast(kind)}); return {}; } } -std::optional ExpressionAnalyzer::Analyze( +template<> std::optional AnalyzeHelper(ExpressionAnalyzer &ea, const parser::LiteralConstant &x) { return std::visit( common::visitors{ - [&](const parser::IntLiteralConstant &c) { return Analyze(c); }, + [&](const parser::IntLiteralConstant &c) { return AnalyzeHelper(ea, c); }, + // TODO next [&](const parser::RealLiteralConstant &c) { return AnalyzeHelper(ea, c); }, + // TODO: remaining cases + [&](const auto &) { return std::optional{}; }}, + x.u); +} + +std::optional ExpressionAnalyzer::Analyze( + const parser::Expr &x) { + return std::visit( + common::visitors{ + [&](const parser::LiteralConstant &c) { return AnalyzeHelper(*this, c); }, + // TODO: remaining cases [&](const auto &) { return std::optional{}; }}, x.u); } diff --git a/flang/lib/semantics/expression.h b/flang/lib/semantics/expression.h index 2cbd4feefd67..48c751987dd8 100644 --- a/flang/lib/semantics/expression.h +++ b/flang/lib/semantics/expression.h @@ -25,17 +25,28 @@ namespace Fortran::semantics { class ExpressionAnalyzer { public: - ExpressionAnalyzer(parser::Messages &m, std::uint64_t dIK) - : messages_{m}, defaultIntegerKind_{dIK} {} + using KindParam = std::int64_t; + ExpressionAnalyzer(evaluate::FoldingContext &c, KindParam dIK) + : context_{c}, defaultIntegerKind_{dIK} {} + + evaluate::FoldingContext &context() { return context_; } + KindParam defaultIntegerKind() const { return defaultIntegerKind_; } + + template + void Say(const M &msg) { + if (context_.messages != nullptr) { + context_.messages->Say(context_.at, msg); + } + } + + // Performs semantic checking on an expression. If successful, + // returns its typed expression representation. std::optional Analyze(const parser::Expr &); - std::optional Analyze( - const parser::IntLiteralConstant &); - std::optional Analyze(const parser::LiteralConstant &); + KindParam Analyze(const std::optional &, KindParam defaultKind, KindParam kanjiKind = -1 /* not allowed here */); private: - parser::Messages &messages_; - const parser::CharBlock at_; - std::uint64_t defaultIntegerKind_{4}; + evaluate::FoldingContext context_; + KindParam defaultIntegerKind_{4}; }; } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_EXPRESSION_H_ diff --git a/flang/lib/semantics/type.h b/flang/lib/semantics/type.h index e89fa37f6662..e50f5a2a225b 100644 --- a/flang/lib/semantics/type.h +++ b/flang/lib/semantics/type.h @@ -42,7 +42,7 @@ leaves are concrete types: DerivedTypeSpec TypeSpec classes are immutable. For intrinsic types (except character) there -are a limited number of instances -- one for each kind. +is a limited number of instances -- one for each kind. A DerivedTypeSpec is based on a DerivedTypeDef (from a derived type statement) with kind and len parameter values provided.