From 9215c0b2a6d504519a8db7fac1ebf63c6a6b2993 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 21 Jan 2020 07:41:52 -0800 Subject: [PATCH 01/24] Add clang-format files for FIR source (LLVM style) Note: This commit does not reflect an actual work log, it is a feature based split of the changes done in the FIR experimental branch. The related work log can be found in the commits between: https://github.com/schweitzpgi/f18/commit/8c320e3bf2c3e9cdac66c81db3bf4634bf972e1d and: https://github.com/schweitzpgi/f18/commit/9b9ea05f9a75608c7bb5372c56bf7b9363569a69 --- .clang-format | 2 +- include/fir/.clang-format | 2 ++ include/flang/lower/.clang-format | 2 ++ include/flang/optimizer/.clang-format | 2 ++ lib/fir/.clang-format | 2 ++ lib/lower/.clang-format | 2 ++ lib/optimizer/.clang-format | 2 ++ tools/bbc/.clang-format | 2 ++ tools/tco/.clang-format | 2 ++ 9 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 include/fir/.clang-format create mode 100644 include/flang/lower/.clang-format create mode 100644 include/flang/optimizer/.clang-format create mode 100644 lib/fir/.clang-format create mode 100644 lib/lower/.clang-format create mode 100644 lib/optimizer/.clang-format create mode 100644 tools/bbc/.clang-format create mode 100644 tools/tco/.clang-format diff --git a/.clang-format b/.clang-format index 21fb1ae51ac5..26741c32c6d4 100644 --- a/.clang-format +++ b/.clang-format @@ -16,7 +16,7 @@ FixNamespaceComments: false IncludeCategories: - Regex: '^<' Priority: 4 - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + - Regex: '^"(llvm|llvm-c|clang|clang-c|fir|mlir|mlir-c)/' Priority: 3 - Regex: '^"(flang|\.\.)/' Priority: 2 diff --git a/include/fir/.clang-format b/include/fir/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/include/fir/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes diff --git a/include/flang/lower/.clang-format b/include/flang/lower/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/include/flang/lower/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes diff --git a/include/flang/optimizer/.clang-format b/include/flang/optimizer/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/include/flang/optimizer/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes diff --git a/lib/fir/.clang-format b/lib/fir/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/lib/fir/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes diff --git a/lib/lower/.clang-format b/lib/lower/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/lib/lower/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes diff --git a/lib/optimizer/.clang-format b/lib/optimizer/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/lib/optimizer/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes diff --git a/tools/bbc/.clang-format b/tools/bbc/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/tools/bbc/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes diff --git a/tools/tco/.clang-format b/tools/tco/.clang-format new file mode 100644 index 000000000000..a74fda4b6734 --- /dev/null +++ b/tools/tco/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes From c36740a747d01885027c86fead0448d161fb4b4f Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 28 Jan 2020 04:58:30 -0800 Subject: [PATCH 02/24] Add ASTBuilder structure to help lowering the parse-tree The ASTBuilder structure is a temporary data structure that is meant to be built from the parse tree just before lowering to FIR and that will be deleted just afterwards. It is not meant to perfrom optimization analysis and transformations. It only provides temporary information, such as label target information or parse tree parent nodes, that is meant to be used to lower the parse tree structure into FIR operations. A pretty printer is available to visualize this data structure. Note: This commit does not reflect an actual work log, it is a feature based split of the changes done in the FIR experimental branch. The related work log can be found in the commits between: 864898cbe509d032abfe1172ec367dbd3dd92bc1 and 137c23da9c64cf90584cf81fd646053a69e91f63 --- include/flang/lower/ASTBuilder.h | 332 ++++++++++++ lib/CMakeLists.txt | 1 + lib/lower/ASTBuilder.cpp | 872 +++++++++++++++++++++++++++++++ lib/lower/CMakeLists.txt | 15 + 4 files changed, 1220 insertions(+) create mode 100644 include/flang/lower/ASTBuilder.h create mode 100644 lib/lower/ASTBuilder.cpp create mode 100644 lib/lower/CMakeLists.txt diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h new file mode 100644 index 000000000000..9dc1ce713fbc --- /dev/null +++ b/include/flang/lower/ASTBuilder.h @@ -0,0 +1,332 @@ +//===-- lib/lower/ast-builder.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_LOWER_AST_BUILDER_H_ +#define FORTRAN_LOWER_AST_BUILDER_H_ + +#include "flang/parser/parse-tree.h" +#include "flang/semantics/scope.h" +#include "llvm/Support/raw_ostream.h" + +namespace Fortran::lower { +namespace AST { + +struct Evaluation; +struct Program; +struct ModuleLikeUnit; +struct FunctionLikeUnit; + +using ParentType = + std::variant; + +enum class CFGAnnotation { + None, + Goto, + CondGoto, + IndGoto, + IoSwitch, + Switch, + Iterative, + FirStructuredOp, + Return, + Terminate +}; + +/// Compiler-generated jump +/// +/// This is used to convert implicit control-flow edges to explicit form in the +/// decorated AST +struct CGJump { + CGJump(Evaluation *to) : target{to} {} + Evaluation *target{nullptr}; +}; + +/// is `A` a construct (or directive)? +template +constexpr static bool isConstruct() { + return std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; +} + +/// Function-like units can contains lists of evaluations. These can be +/// (simple) statements or constructs, where a construct contains its own +/// evaluations. +struct Evaluation { + using EvalVariant = std::variant< + // action statements + const parser::AllocateStmt *, const parser::AssignmentStmt *, + const parser::BackspaceStmt *, const parser::CallStmt *, + const parser::CloseStmt *, const parser::ContinueStmt *, + const parser::CycleStmt *, const parser::DeallocateStmt *, + const parser::EndfileStmt *, const parser::EventPostStmt *, + const parser::EventWaitStmt *, const parser::ExitStmt *, + const parser::FailImageStmt *, const parser::FlushStmt *, + const parser::FormTeamStmt *, const parser::GotoStmt *, + const parser::IfStmt *, const parser::InquireStmt *, + const parser::LockStmt *, const parser::NullifyStmt *, + const parser::OpenStmt *, const parser::PointerAssignmentStmt *, + const parser::PrintStmt *, const parser::ReadStmt *, + const parser::ReturnStmt *, const parser::RewindStmt *, + const parser::StopStmt *, const parser::SyncAllStmt *, + const parser::SyncImagesStmt *, const parser::SyncMemoryStmt *, + const parser::SyncTeamStmt *, const parser::UnlockStmt *, + const parser::WaitStmt *, const parser::WhereStmt *, + const parser::WriteStmt *, const parser::ComputedGotoStmt *, + const parser::ForallStmt *, const parser::ArithmeticIfStmt *, + const parser::AssignStmt *, const parser::AssignedGotoStmt *, + const parser::PauseStmt *, + // compiler generated ops + CGJump, + // other statements + const parser::FormatStmt *, const parser::EntryStmt *, + const parser::DataStmt *, const parser::NamelistStmt *, + // constructs + const parser::AssociateConstruct *, const parser::BlockConstruct *, + const parser::CaseConstruct *, const parser::ChangeTeamConstruct *, + const parser::CriticalConstruct *, const parser::DoConstruct *, + const parser::IfConstruct *, const parser::SelectRankConstruct *, + const parser::SelectTypeConstruct *, const parser::WhereConstruct *, + const parser::ForallConstruct *, const parser::CompilerDirective *, + const parser::OpenMPConstruct *, const parser::OmpEndLoopDirective *, + // construct statements + const parser::AssociateStmt *, const parser::EndAssociateStmt *, + const parser::BlockStmt *, const parser::EndBlockStmt *, + const parser::SelectCaseStmt *, const parser::CaseStmt *, + const parser::EndSelectStmt *, const parser::ChangeTeamStmt *, + const parser::EndChangeTeamStmt *, const parser::CriticalStmt *, + const parser::EndCriticalStmt *, const parser::NonLabelDoStmt *, + const parser::EndDoStmt *, const parser::IfThenStmt *, + const parser::ElseIfStmt *, const parser::ElseStmt *, + const parser::EndIfStmt *, const parser::SelectRankStmt *, + const parser::SelectRankCaseStmt *, const parser::SelectTypeStmt *, + const parser::TypeGuardStmt *, const parser::WhereConstructStmt *, + const parser::MaskedElsewhereStmt *, const parser::ElsewhereStmt *, + const parser::EndWhereStmt *, const parser::ForallConstructStmt *, + const parser::EndForallStmt *>; + + Evaluation() = delete; + Evaluation(const Evaluation &) = default; + + /// General ctor + template + Evaluation(const A &a, const parser::CharBlock &pos, + const std::optional &lab, const ParentType &p) + : u{&a}, parent{p}, pos{pos}, lab{lab} {} + + /// Compiler-generated jump + Evaluation(const CGJump &jump, const ParentType &p) + : u{jump}, parent{p}, cfg{CFGAnnotation::Goto} {} + + /// Construct ctor + template + Evaluation(const A &a, const ParentType &parent) : u{&a}, parent{parent} { + static_assert(AST::isConstruct(), "must be a construct"); + } + + /// is `A` executable (an action statement or compiler generated)? + template + constexpr static bool isAction(const A &a) { + return !AST::isConstruct() && !isOther(a); + } + + /// is `A` a compiler-generated evaluation? + template + constexpr static bool isGenerated(const A &) { + return std::is_same_v; + } + + /// is `A` not an executable statement? + template + constexpr static bool isOther(const A &) { + return std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + } + + constexpr bool isActionStmt() const { + return std::visit(common::visitors{ + [](auto *p) { return isAction(*p); }, + [](auto &r) { return isGenerated(r); }, + }, + u); + } + + constexpr bool isStmt() const { + return std::visit(common::visitors{ + [](auto *p) { return isAction(*p) || isOther(*p); }, + [](auto &r) { return isGenerated(r); }, + }, + u); + } + constexpr bool isConstruct() const { return !isStmt(); } + + /// Set the type of originating control flow type for this evaluation. + void setCFG(CFGAnnotation a, Evaluation *cstr) { + cfg = a; + setBranches(cstr); + } + + /// Is this evaluation a control-flow origin? (The AST must be annotated) + bool isControlOrigin() const { return cfg != CFGAnnotation::None; } + + /// Is this evaluation a control-flow target? (The AST must be annotated) + bool isControlTarget() const { return isTarget; } + + /// Set the containsBranches flag iff this evaluation (a construct) contains + /// control flow + void setBranches() { containsBranches = true; } + + constexpr std::list *getConstructEvals() { + return isStmt() ? nullptr : subs; + } + + /// Set that the construct `cstr` (if not a nullptr) has branches. + static void setBranches(Evaluation *cstr) { + if (cstr) { + cstr->setBranches(); + } + } + + EvalVariant u; + ParentType parent; + parser::CharBlock pos; + std::optional lab; + std::list *subs{nullptr}; // construct sub-statements + CFGAnnotation cfg{CFGAnnotation::None}; + bool isTarget{false}; // this evaluation is a control target + bool containsBranches{false}; // construct contains branches +}; + +/// A program is a list of program units. +/// These units can be function like, module like, or block data +struct ProgramUnit { + template + ProgramUnit(A *ptr, const ParentType &parent) : p{ptr}, parent{parent} {} + + std::variant + p; + ParentType parent; +}; + +/// Function-like units have similar structure. They all can contain executable +/// statements. +struct FunctionLikeUnit : public ProgramUnit { + // wrapper statements for function-like syntactic structures + using FunctionStatement = + std::variant *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *>; + + FunctionLikeUnit(const parser::MainProgram &f, const ParentType &parent); + FunctionLikeUnit(const parser::FunctionSubprogram &f, + const ParentType &parent); + FunctionLikeUnit(const parser::SubroutineSubprogram &f, + const ParentType &parent); + FunctionLikeUnit(const parser::SeparateModuleSubprogram &f, + const ParentType &parent); + + bool isMainProgram() { + return std::get_if *>( + &funStmts.back()); + } + const parser::FunctionStmt *isFunction() { + return isA(); + } + const parser::SubroutineStmt *isSubroutine() { + return isA(); + } + const parser::MpSubprogramStmt *isMPSubp() { + return isA(); + } + + const semantics::Scope *scope{nullptr}; // scope from front-end + std::list funStmts; // begin/end pair + std::list evals; // statements + std::list funcs; // internal procedures + +private: + template + const A *isA() { + if (auto p = std::get_if *>(&funStmts.front())) { + return &(*p)->statement; + } + return nullptr; + } +}; + +/// Module-like units have similar structure. They all can contain a list of +/// function-like units. +struct ModuleLikeUnit : public ProgramUnit { + // wrapper statements for module-like syntactic structures + using ModuleStatement = + std::variant *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *>; + + ModuleLikeUnit(const parser::Module &m, const ParentType &parent); + ModuleLikeUnit(const parser::Submodule &m, const ParentType &parent); + ~ModuleLikeUnit() = default; + + const semantics::Scope *scope{nullptr}; + std::list modStmts; + std::list funcs; +}; + +struct BlockDataUnit : public ProgramUnit { + BlockDataUnit(const parser::BlockData &db, const ParentType &parent); +}; + +/// A Program is the top-level AST +struct Program { + using Units = std::variant; + + std::list &getUnits() { return units; } + +private: + std::list units; +}; + +} // namespace AST + +/// Create an AST from the parse tree +AST::Program *createAST(const parser::Program &root); + +/// Decorate the AST with control flow annotations +/// +/// The AST must be decorated with control-flow annotations to prepare it for +/// use in generating a CFG-like structure. +void annotateControl(AST::Program &ast); + +void dumpAST(llvm::raw_ostream &o, AST::Program &ast); + +} // namespace Fortran::lower + +#endif // FORTRAN_LOWER_AST_BUILDER_H_ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 343195bae2b0..35c3e139b1bf 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -9,5 +9,6 @@ add_subdirectory(common) add_subdirectory(evaluate) add_subdirectory(decimal) +add_subdirectory(lower) add_subdirectory(parser) add_subdirectory(semantics) diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp new file mode 100644 index 000000000000..c234c8f02d2b --- /dev/null +++ b/lib/lower/ASTBuilder.cpp @@ -0,0 +1,872 @@ +//===-- lib/lower/ast-builder.cc ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/lower/ASTBuilder.h" +#include "flang/parser/parse-tree-visitor.h" +#include +#include + +/// Build a light-weight AST to help with lowering to FIR. The AST will +/// capture pointers back into the parse tree, so the parse tree data structure +/// may not be changed between the construction of the AST and all of +/// its uses. +/// +/// The AST captures a structured view of the program. The program is a list of +/// units. Function like units will contain lists of evaluations. Evaluations +/// are either statements or constructs, where a construct contains a list of +/// evaluations. The resulting AST structure can then be used to create FIR. + +namespace Br = Fortran::lower; +namespace Co = Fortran::common; +namespace L = llvm; +namespace Pa = Fortran::parser; + +using namespace Fortran; +using namespace Br; + +namespace { + +/// The instantiation of a parse tree visitor (Pre and Post) is extremely +/// expensive in terms of compile and link time, so one goal here is to limit +/// the bridge to one such instantiation. +class ASTBuilder { +public: + ASTBuilder() { + pgm = new AST::Program; + parents.push_back(pgm); + } + + /// Get the result + AST::Program *result() { return pgm; } + + template + constexpr bool Pre(const A &) { + return true; + } + template + constexpr void Post(const A &) {} + + // Module like + + bool Pre(const Pa::Module &x) { return enterModule(x); } + bool Pre(const Pa::Submodule &x) { return enterModule(x); } + + void Post(const Pa::Module &) { exitModule(); } + void Post(const Pa::Submodule &) { exitModule(); } + + // Function like + + bool Pre(const Pa::MainProgram &x) { return enterFunc(x); } + bool Pre(const Pa::FunctionSubprogram &x) { return enterFunc(x); } + bool Pre(const Pa::SubroutineSubprogram &x) { return enterFunc(x); } + bool Pre(const Pa::SeparateModuleSubprogram &x) { return enterFunc(x); } + + void Post(const Pa::MainProgram &) { exitFunc(); } + void Post(const Pa::FunctionSubprogram &) { exitFunc(); } + void Post(const Pa::SubroutineSubprogram &) { exitFunc(); } + void Post(const Pa::SeparateModuleSubprogram &) { exitFunc(); } + + // Block data + + void Post(const Pa::BlockData &x) { + AST::BlockDataUnit unit{x, parents.back()}; + addUnit(unit); + } + + // + // Action statements + // + + void Post(const Pa::Statement &s) { + addEval(makeEvalAction(s)); + } + void Post(const Pa::UnlabeledStatement &s) { + addEval(makeEvalAction(s)); + } + + // + // Non-executable statements + // + + void Post(const Pa::Statement> &s) { + addEval(makeEvalIndirect(s)); + } + void Post(const Pa::Statement> &s) { + addEval(makeEvalIndirect(s)); + } + void Post(const Pa::Statement> &s) { + addEval(makeEvalIndirect(s)); + } + void Post(const Pa::Statement> &s) { + addEval(makeEvalIndirect(s)); + } + + // + // Construct statements + // + + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + void Post(const Pa::Statement &s) { + addEval(makeEvalDirect(s)); + } + // Get rid of production wrapper + void Post(const Pa::UnlabeledStatement &s) { + addEval(std::visit( + [&](const auto &x) { + return AST::Evaluation{x, s.source, {}, parents.back()}; + }, + s.statement.u)); + } + void Post(const Pa::Statement &s) { + addEval(std::visit( + [&](const auto &x) { + return AST::Evaluation{x, s.source, s.label, parents.back()}; + }, + s.statement.u)); + } + + // + // Constructs (enter and exit) + // + + bool Pre(const Pa::AssociateConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::BlockConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::CaseConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::ChangeTeamConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::CriticalConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::DoConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::IfConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::SelectRankConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::SelectTypeConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::WhereConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::ForallConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::CompilerDirective &c) { return enterConstruct(c); } + bool Pre(const Pa::OpenMPConstruct &c) { return enterConstruct(c); } + bool Pre(const Pa::OmpEndLoopDirective &c) { return enterConstruct(c); } + + void Post(const Pa::AssociateConstruct &) { exitConstruct(); } + void Post(const Pa::BlockConstruct &) { exitConstruct(); } + void Post(const Pa::CaseConstruct &) { exitConstruct(); } + void Post(const Pa::ChangeTeamConstruct &) { exitConstruct(); } + void Post(const Pa::CriticalConstruct &) { exitConstruct(); } + void Post(const Pa::DoConstruct &) { exitConstruct(); } + void Post(const Pa::IfConstruct &) { exitConstruct(); } + void Post(const Pa::SelectRankConstruct &) { exitConstruct(); } + void Post(const Pa::SelectTypeConstruct &) { exitConstruct(); } + void Post(const Pa::WhereConstruct &) { exitConstruct(); } + void Post(const Pa::ForallConstruct &) { exitConstruct(); } + void Post(const Pa::CompilerDirective &) { exitConstruct(); } + void Post(const Pa::OpenMPConstruct &) { exitConstruct(); } + void Post(const Pa::OmpEndLoopDirective &) { exitConstruct(); } + +private: + // ActionStmt has a couple of non-conforming cases, which get handled + // explicitly here. The other cases use an Indirection, which we discard in + // the AST. + AST::Evaluation makeEvalAction(const Pa::Statement &s) { + return std::visit( + Co::visitors{ + [&](const Pa::ContinueStmt &x) { + return AST::Evaluation{x, s.source, s.label, parents.back()}; + }, + [&](const Pa::FailImageStmt &x) { + return AST::Evaluation{x, s.source, s.label, parents.back()}; + }, + [&](const auto &x) { + return AST::Evaluation{x.value(), s.source, s.label, + parents.back()}; + }, + }, + s.statement.u); + } + AST::Evaluation + makeEvalAction(const Pa::UnlabeledStatement &s) { + return std::visit( + Co::visitors{ + [&](const Pa::ContinueStmt &x) { + return AST::Evaluation{x, s.source, {}, parents.back()}; + }, + [&](const Pa::FailImageStmt &x) { + return AST::Evaluation{x, s.source, {}, parents.back()}; + }, + [&](const auto &x) { + return AST::Evaluation{x.value(), s.source, {}, parents.back()}; + }, + }, + s.statement.u); + } + + template + AST::Evaluation makeEvalIndirect(const Pa::Statement> &s) { + return AST::Evaluation{s.statement.value(), s.source, s.label, + parents.back()}; + } + + template + AST::Evaluation makeEvalDirect(const Pa::Statement &s) { + return AST::Evaluation{s.statement, s.source, s.label, parents.back()}; + } + + // When we enter a function-like structure, we want to build a new unit and + // set the builder's cursors to point to it. + template + bool enterFunc(const A &f) { + auto &unit = addFunc(AST::FunctionLikeUnit{f, parents.back()}); + funclist = &unit.funcs; + pushEval(&unit.evals); + parents.emplace_back(&unit); + return true; + } + + void exitFunc() { + popEval(); + funclist = nullptr; + parents.pop_back(); + } + + // When we enter a construct structure, we want to build a new construct and + // set the builder's evaluation cursor to point to it. + template + bool enterConstruct(const A &c) { + auto &con = addEval(AST::Evaluation{c, parents.back()}); + con.subs = new std::list(); + pushEval(con.subs); + parents.emplace_back(&con); + return true; + } + + void exitConstruct() { + popEval(); + parents.pop_back(); + } + + // When we enter a module structure, we want to build a new module and + // set the builder's function cursor to point to it. + template + bool enterModule(const A &f) { + auto &unit = addUnit(AST::ModuleLikeUnit{f, parents.back()}); + funclist = &unit.funcs; + parents.emplace_back(&unit); + return true; + } + + void exitModule() { + funclist = nullptr; + parents.pop_back(); + } + + template + A &addUnit(const A &unit) { + pgm->getUnits().emplace_back(unit); + return std::get(pgm->getUnits().back()); + } + + template + A &addFunc(const A &func) { + if (funclist) { + funclist->emplace_back(func); + return funclist->back(); + } + return addUnit(func); + } + + /// move the Evaluation to the end of the current list + AST::Evaluation &addEval(AST::Evaluation &&eval) { + assert(funclist && "not in a function"); + assert(evallist.size() > 0); + evallist.back()->emplace_back(std::move(eval)); + return evallist.back()->back(); + } + + /// push a new list on the stack of Evaluation lists + void pushEval(std::list *eval) { + assert(funclist && "not in a function"); + assert(eval && eval->empty() && "evaluation list isn't correct"); + evallist.emplace_back(eval); + } + + /// pop the current list and return to the last Evaluation list + void popEval() { + assert(funclist && "not in a function"); + evallist.pop_back(); + } + + AST::Program *pgm; + std::list *funclist{nullptr}; + std::vector *> evallist; + std::vector parents; +}; + +template +constexpr bool hasErrLabel(const A &stmt) { + if constexpr (std::is_same_v || + std::is_same_v) { + for (const auto &control : stmt.controls) { + if (std::holds_alternative(control.u)) { + return true; + } + } + } + if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v) { + for (const auto &spec : stmt.v) { + if (std::holds_alternative(spec.u)) { + return true; + } + } + } + if constexpr (std::is_same_v) { + for (const auto &spec : std::get>(stmt.u)) { + if (std::holds_alternative(spec.u)) { + return true; + } + } + } + return false; +} + +template +constexpr bool hasEorLabel(const A &stmt) { + if constexpr (std::is_same_v || + std::is_same_v) { + for (const auto &control : stmt.controls) { + if (std::holds_alternative(control.u)) { + return true; + } + } + } + if constexpr (std::is_same_v) { + for (const auto &waitSpec : stmt.v) { + if (std::holds_alternative(waitSpec.u)) { + return true; + } + } + } + return false; +} + +template +constexpr bool hasEndLabel(const A &stmt) { + if constexpr (std::is_same_v || + std::is_same_v) { + for (const auto &control : stmt.controls) { + if (std::holds_alternative(control.u)) { + return true; + } + } + } + if constexpr (std::is_same_v) { + for (const auto &waitSpec : stmt.v) { + if (std::holds_alternative(waitSpec.u)) { + return true; + } + } + } + return false; +} + +bool hasAltReturns(const Pa::CallStmt &callStmt) { + const auto &args{std::get>(callStmt.v.t)}; + for (const auto &arg : args) { + const auto &actual{std::get(arg.t)}; + if (std::holds_alternative(actual.u)) { + return true; + } + } + return false; +} + +/// Determine if `callStmt` has alternate returns and if so set `e` to be the +/// origin of a switch-like control flow +void altRet(AST::Evaluation &e, const Pa::CallStmt *callStmt, + AST::Evaluation *cstr) { + if (hasAltReturns(*callStmt)) { + e.setCFG(AST::CFGAnnotation::Switch, cstr); + } +} + +template +void ioLabel(AST::Evaluation &e, const A *s, AST::Evaluation *cstr) { + if (hasErrLabel(*s) || hasEorLabel(*s) || hasEndLabel(*s)) { + e.setCFG(AST::CFGAnnotation::IoSwitch, cstr); + } +} + +void annotateEvalListCFG(std::list &evals, + AST::Evaluation *cstr) { + bool nextIsTarget = false; + for (auto &e : evals) { + e.isTarget = nextIsTarget; + nextIsTarget = false; + if (e.isConstruct()) { + annotateEvalListCFG(*e.getConstructEvals(), &e); + // assume that the entry and exit are both possible branch targets + nextIsTarget = true; + } + if (e.isActionStmt() && e.lab.has_value()) { + e.isTarget = true; + } + std::visit( + Co::visitors{ + [&](const Pa::BackspaceStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::CallStmt *s) { altRet(e, s, cstr); }, + [&](const Pa::CloseStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::CycleStmt *) { + e.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const Pa::EndfileStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::ExitStmt *) { + e.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const Pa::FailImageStmt *) { + e.setCFG(AST::CFGAnnotation::Terminate, cstr); + }, + [&](const Pa::FlushStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::GotoStmt *) { + e.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const Pa::IfStmt *) { + e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const Pa::InquireStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::OpenStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::ReadStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::ReturnStmt *) { + e.setCFG(AST::CFGAnnotation::Return, cstr); + }, + [&](const Pa::RewindStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::StopStmt *) { + e.setCFG(AST::CFGAnnotation::Terminate, cstr); + }, + [&](const Pa::WaitStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::WriteStmt *s) { ioLabel(e, s, cstr); }, + [&](const Pa::ArithmeticIfStmt *) { + e.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const Pa::AssignedGotoStmt *) { + e.setCFG(AST::CFGAnnotation::IndGoto, cstr); + }, + [&](const Pa::ComputedGotoStmt *) { + e.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const Pa::WhereStmt *) { + // fir.loop + fir.where around the next stmt + e.isTarget = true; + e.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const Pa::ForallStmt *) { + // fir.loop around the next stmt + e.isTarget = true; + e.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](AST::CGJump &) { e.setCFG(AST::CFGAnnotation::Goto, cstr); }, + [&](const Pa::EndAssociateStmt *) { e.isTarget = true; }, + [&](const Pa::EndBlockStmt *) { e.isTarget = true; }, + [&](const Pa::SelectCaseStmt *) { + e.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const Pa::CaseStmt *) { e.isTarget = true; }, + [&](const Pa::EndSelectStmt *) { e.isTarget = true; }, + [&](const Pa::EndChangeTeamStmt *) { e.isTarget = true; }, + [&](const Pa::EndCriticalStmt *) { e.isTarget = true; }, + [&](const Pa::NonLabelDoStmt *) { + e.isTarget = true; + e.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const Pa::EndDoStmt *) { + e.isTarget = true; + e.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const Pa::IfThenStmt *) { + e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const Pa::ElseIfStmt *) { + e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const Pa::ElseStmt *) { e.isTarget = true; }, + [&](const Pa::EndIfStmt *) { e.isTarget = true; }, + [&](const Pa::SelectRankStmt *) { + e.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const Pa::SelectRankCaseStmt *) { e.isTarget = true; }, + [&](const Pa::SelectTypeStmt *) { + e.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const Pa::TypeGuardStmt *) { e.isTarget = true; }, + [&](const Pa::WhereConstruct *) { + // mark the WHERE as if it were a DO loop + e.isTarget = true; + e.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const Pa::WhereConstructStmt *) { + e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const Pa::MaskedElsewhereStmt *) { + e.isTarget = true; + e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const Pa::ElsewhereStmt *) { e.isTarget = true; }, + [&](const Pa::EndWhereStmt *) { e.isTarget = true; }, + [&](const Pa::ForallConstructStmt *) { + e.isTarget = true; + e.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const Pa::EndForallStmt *) { e.isTarget = true; }, + [](const auto *) { /* do nothing */ }, + }, + e.u); + } +} + +/// Annotate the AST with CFG source decorations (see CFGAnnotation) and mark +/// potential branch targets +inline void annotateFuncCFG(AST::FunctionLikeUnit &flu) { + annotateEvalListCFG(flu.evals, nullptr); +} + +L::StringRef evalName(AST::Evaluation &e) { + return std::visit( + Co::visitors{ + [](const Pa::AllocateStmt *) { return "AllocateStmt"; }, + [](const Pa::ArithmeticIfStmt *) { return "ArithmeticIfStmt"; }, + [](const Pa::AssignedGotoStmt *) { return "AssignedGotoStmt"; }, + [](const Pa::AssignmentStmt *) { return "AssignmentStmt"; }, + [](const Pa::AssignStmt *) { return "AssignStmt"; }, + [](const Pa::BackspaceStmt *) { return "BackspaceStmt"; }, + [](const Pa::CallStmt *) { return "CallStmt"; }, + [](const Pa::CloseStmt *) { return "CloseStmt"; }, + [](const Pa::ComputedGotoStmt *) { return "ComputedGotoStmt"; }, + [](const Pa::ContinueStmt *) { return "ContinueStmt"; }, + [](const Pa::CycleStmt *) { return "CycleStmt"; }, + [](const Pa::DeallocateStmt *) { return "DeallocateStmt"; }, + [](const Pa::EndfileStmt *) { return "EndfileStmt"; }, + [](const Pa::EventPostStmt *) { return "EventPostStmt"; }, + [](const Pa::EventWaitStmt *) { return "EventWaitStmt"; }, + [](const Pa::ExitStmt *) { return "ExitStmt"; }, + [](const Pa::FailImageStmt *) { return "FailImageStmt"; }, + [](const Pa::FlushStmt *) { return "FlushStmt"; }, + [](const Pa::ForallStmt *) { return "ForallStmt"; }, + [](const Pa::FormTeamStmt *) { return "FormTeamStmt"; }, + [](const Pa::GotoStmt *) { return "GotoStmt"; }, + [](const Pa::IfStmt *) { return "IfStmt"; }, + [](const Pa::InquireStmt *) { return "InquireStmt"; }, + [](const Pa::LockStmt *) { return "LockStmt"; }, + [](const Pa::NullifyStmt *) { return "NullifyStmt"; }, + [](const Pa::OpenStmt *) { return "OpenStmt"; }, + [](const Pa::PauseStmt *) { return "PauseStmt"; }, + [](const Pa::PointerAssignmentStmt *) { + return "PointerAssignmentStmt"; + }, + [](const Pa::PrintStmt *) { return "PrintStmt"; }, + [](const Pa::ReadStmt *) { return "ReadStmt"; }, + [](const Pa::ReturnStmt *) { return "ReturnStmt"; }, + [](const Pa::RewindStmt *) { return "RewindStmt"; }, + [](const Pa::StopStmt *) { return "StopStmt"; }, + [](const Pa::SyncAllStmt *) { return "SyncAllStmt"; }, + [](const Pa::SyncImagesStmt *) { return "SyncImagesStmt"; }, + [](const Pa::SyncMemoryStmt *) { return "SyncMemoryStmt"; }, + [](const Pa::SyncTeamStmt *) { return "SyncTeamStmt"; }, + [](const Pa::UnlockStmt *) { return "UnlockStmt"; }, + [](const Pa::WaitStmt *) { return "WaitStmt"; }, + [](const Pa::WhereStmt *) { return "WhereStmt"; }, + [](const Pa::WriteStmt *) { return "WriteStmt"; }, + + [](const AST::CGJump) { return "CGJump"; }, + + [](const Pa::DataStmt *) { return "DataStmt"; }, + [](const Pa::EntryStmt *) { return "EntryStmt"; }, + [](const Pa::FormatStmt *) { return "FormatStmt"; }, + [](const Pa::NamelistStmt *) { return "NamelistStmt"; }, + + [](const Pa::AssociateConstruct *) { return "AssociateConstruct"; }, + [](const Pa::BlockConstruct *) { return "BlockConstruct"; }, + [](const Pa::CaseConstruct *) { return "CaseConstruct"; }, + [](const Pa::ChangeTeamConstruct *) { return "ChangeTeamConstruct"; }, + [](const Pa::CompilerDirective *) { return "CompilerDirective"; }, + [](const Pa::CriticalConstruct *) { return "CriticalConstruct"; }, + [](const Pa::DoConstruct *) { return "DoConstruct"; }, + [](const Pa::ForallConstruct *) { return "ForallConstruct"; }, + [](const Pa::IfConstruct *) { return "IfConstruct"; }, + [](const Pa::OmpEndLoopDirective *) { return "OmpEndLoopDirective"; }, + [](const Pa::OpenMPConstruct *) { return "OpenMPConstruct"; }, + [](const Pa::SelectRankConstruct *) { return "SelectRankConstruct"; }, + [](const Pa::SelectTypeConstruct *) { return "SelectTypeConstruct"; }, + [](const Pa::WhereConstruct *) { return "WhereConstruct"; }, + + [](const Pa::AssociateStmt *) { return "AssociateStmt"; }, + [](const Pa::BlockStmt *) { return "BlockStmt"; }, + [](const Pa::CaseStmt *) { return "CaseStmt"; }, + [](const Pa::ChangeTeamStmt *) { return "ChangeTeamStmt"; }, + [](const Pa::CriticalStmt *) { return "CriticalStmt"; }, + [](const Pa::ElseIfStmt *) { return "ElseIfStmt"; }, + [](const Pa::ElseStmt *) { return "ElseStmt"; }, + [](const Pa::ElsewhereStmt *) { return "ElsewhereStmt"; }, + [](const Pa::EndAssociateStmt *) { return "EndAssociateStmt"; }, + [](const Pa::EndBlockStmt *) { return "EndBlockStmt"; }, + [](const Pa::EndChangeTeamStmt *) { return "EndChangeTeamStmt"; }, + [](const Pa::EndCriticalStmt *) { return "EndCriticalStmt"; }, + [](const Pa::EndDoStmt *) { return "EndDoStmt"; }, + [](const Pa::EndForallStmt *) { return "EndForallStmt"; }, + [](const Pa::EndIfStmt *) { return "EndIfStmt"; }, + [](const Pa::EndSelectStmt *) { return "EndSelectStmt"; }, + [](const Pa::EndWhereStmt *) { return "EndWhereStmt"; }, + [](const Pa::ForallConstructStmt *) { return "ForallConstructStmt"; }, + [](const Pa::IfThenStmt *) { return "IfThenStmt"; }, + [](const Pa::MaskedElsewhereStmt *) { return "MaskedElsewhereStmt"; }, + [](const Pa::NonLabelDoStmt *) { return "NonLabelDoStmt"; }, + [](const Pa::SelectCaseStmt *) { return "SelectCaseStmt"; }, + [](const Pa::SelectRankCaseStmt *) { return "SelectRankCaseStmt"; }, + [](const Pa::SelectRankStmt *) { return "SelectRankStmt"; }, + [](const Pa::SelectTypeStmt *) { return "SelectTypeStmt"; }, + [](const Pa::TypeGuardStmt *) { return "TypeGuardStmt"; }, + [](const Pa::WhereConstructStmt *) { return "WhereConstructStmt"; }, + }, + e.u); +} + +void dumpEvalList(L::raw_ostream &o, std::list &evals, + int indent = 1) { + static const std::string white{" ++"}; + std::string indentString{white.substr(0, indent * 2)}; + for (AST::Evaluation &e : evals) { + L::StringRef name{evalName(e)}; + if (e.isConstruct()) { + o << indentString << "<<" << name << ">>\n"; + dumpEvalList(o, *e.getConstructEvals(), indent + 1); + o << indentString << "<>\n"; + } else { + o << indentString << name << ": " << e.pos.ToString() << '\n'; + } + } +} + +void dumpFunctionLikeUnit(L::raw_ostream &o, AST::FunctionLikeUnit &flu) { + L::StringRef unitKind{}; + std::string name{}; + std::string header{}; + std::visit(Co::visitors{ + [&](const Pa::Statement *s) { + unitKind = "Program"; + name = s->statement.v.ToString(); + }, + [&](const Pa::Statement *s) { + unitKind = "Function"; + name = std::get(s->statement.t).ToString(); + header = s->source.ToString(); + }, + [&](const Pa::Statement *s) { + unitKind = "Subroutine"; + name = std::get(s->statement.t).ToString(); + header = s->source.ToString(); + }, + [&](const Pa::Statement *s) { + unitKind = "MpSubprogram"; + name = s->statement.v.ToString(); + header = s->source.ToString(); + }, + [&](auto *) { + if (std::get_if *>( + &flu.funStmts.back())) { + unitKind = "Program"; + name = ""; + } else { + unitKind = ">>>>> Error - no program unit <<<<<"; + } + }, + }, + flu.funStmts.front()); + o << unitKind << ' ' << name; + if (header.size()) { + o << ": " << header; + } + o << '\n'; + dumpEvalList(o, flu.evals); + o << "End" << unitKind << ' ' << name << "\n\n"; +} + +} // namespace + +Br::AST::FunctionLikeUnit::FunctionLikeUnit(const Pa::MainProgram &f, + const AST::ParentType &parent) + : ProgramUnit{&f, parent} { + auto &ps{std::get>>(f.t)}; + if (ps.has_value()) { + const Pa::Statement &s{ps.value()}; + funStmts.push_back(&s); + } + funStmts.push_back(&std::get>(f.t)); +} + +Br::AST::FunctionLikeUnit::FunctionLikeUnit(const Pa::FunctionSubprogram &f, + const AST::ParentType &parent) + : ProgramUnit{&f, parent} { + funStmts.push_back(&std::get>(f.t)); + funStmts.push_back(&std::get>(f.t)); +} + +Br::AST::FunctionLikeUnit::FunctionLikeUnit(const Pa::SubroutineSubprogram &f, + const AST::ParentType &parent) + : ProgramUnit{&f, parent} { + funStmts.push_back(&std::get>(f.t)); + funStmts.push_back(&std::get>(f.t)); +} + +Br::AST::FunctionLikeUnit::FunctionLikeUnit( + const Pa::SeparateModuleSubprogram &f, const AST::ParentType &parent) + : ProgramUnit{&f, parent} { + funStmts.push_back(&std::get>(f.t)); + funStmts.push_back(&std::get>(f.t)); +} + +Br::AST::ModuleLikeUnit::ModuleLikeUnit(const Pa::Module &m, + const AST::ParentType &parent) + : ProgramUnit{&m, parent} { + modStmts.push_back(&std::get>(m.t)); + modStmts.push_back(&std::get>(m.t)); +} + +Br::AST::ModuleLikeUnit::ModuleLikeUnit(const Pa::Submodule &m, + const AST::ParentType &parent) + : ProgramUnit{&m, parent} { + modStmts.push_back(&std::get>(m.t)); + modStmts.push_back(&std::get>(m.t)); +} + +Br::AST::BlockDataUnit::BlockDataUnit(const Pa::BlockData &db, + const AST::ParentType &parent) + : ProgramUnit{&db, parent} {} + +AST::Program *Br::createAST(const Pa::Program &root) { + ASTBuilder walker; + Walk(root, walker); + return walker.result(); +} + +void Br::annotateControl(AST::Program &ast) { + for (auto &unit : ast.getUnits()) { + std::visit(Co::visitors{ + [](AST::BlockDataUnit &) {}, + [](AST::FunctionLikeUnit &f) { + annotateFuncCFG(f); + for (auto &s : f.funcs) { + annotateFuncCFG(s); + } + }, + [](AST::ModuleLikeUnit &u) { + for (auto &f : u.funcs) { + annotateFuncCFG(f); + } + }, + }, + unit); + } +} + +/// Dump an AST. +void Br::dumpAST(L::raw_ostream &o, AST::Program &ast) { + for (auto &unit : ast.getUnits()) { + std::visit( + Co::visitors{ + [&](AST::BlockDataUnit &) { o << "BlockData\nEndBlockData\n\n"; }, + [&](AST::FunctionLikeUnit &f) { + dumpFunctionLikeUnit(o, f); + for (auto &f : f.funcs) { + dumpFunctionLikeUnit(o, f); + } + }, + [&](AST::ModuleLikeUnit &u) { + for (auto &f : u.funcs) { + dumpFunctionLikeUnit(o, f); + } + }, + }, + unit); + } +} diff --git a/lib/lower/CMakeLists.txt b/lib/lower/CMakeLists.txt new file mode 100644 index 000000000000..fa0b3b4d2ad0 --- /dev/null +++ b/lib/lower/CMakeLists.txt @@ -0,0 +1,15 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error") + +add_library(FortranLower + ASTBuilder.cpp +) + +target_link_libraries(FortranLower + LLVMSupport +) + +install (TARGETS FortranLower + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) From 5c3afc019d63a1ae3c52d59039ad92e7520b178e Mon Sep 17 00:00:00 2001 From: Eric Schweitz Date: Tue, 28 Jan 2020 14:59:42 -0800 Subject: [PATCH 03/24] review comments Review: https://github.com/flang-compiler/f18/pull/959 Fixes file names in LLVM copyright. --- include/flang/lower/ASTBuilder.h | 2 +- lib/lower/ASTBuilder.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 9dc1ce713fbc..3e7df46a7799 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -1,4 +1,4 @@ -//===-- lib/lower/ast-builder.h ---------------------------------*- C++ -*-===// +//===-- include/flang/lower/AstBuilder.h ------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index c234c8f02d2b..ead8243ccedd 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -1,4 +1,4 @@ -//===-- lib/lower/ast-builder.cc ------------------------------------------===// +//===-- lib/lower/AstBuilder.cc -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. From e6345f5c3ae6e521fb8994e501999a036cfb98a9 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Wed, 29 Jan 2020 06:25:40 -0800 Subject: [PATCH 04/24] Address PR959 review comments - change Evaluation ctor argument order to match member order - db -> bd for BlockData argument name - Use dump-parse-tree.h for the AST pretty printer. --- include/flang/lower/ASTBuilder.h | 6 +- include/flang/parser/dump-parse-tree.h | 6 +- lib/lower/ASTBuilder.cpp | 129 ++++--------------------- 3 files changed, 26 insertions(+), 115 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 3e7df46a7799..00ec879185d0 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -126,8 +126,8 @@ struct Evaluation { /// General ctor template - Evaluation(const A &a, const parser::CharBlock &pos, - const std::optional &lab, const ParentType &p) + Evaluation(const A &a, const ParentType &p, const parser::CharBlock &pos, + const std::optional &lab) : u{&a}, parent{p}, pos{pos}, lab{lab} {} /// Compiler-generated jump @@ -301,7 +301,7 @@ struct ModuleLikeUnit : public ProgramUnit { }; struct BlockDataUnit : public ProgramUnit { - BlockDataUnit(const parser::BlockData &db, const ParentType &parent); + BlockDataUnit(const parser::BlockData &bd, const ParentType &parent); }; /// A Program is the top-level AST diff --git a/include/flang/parser/dump-parse-tree.h b/include/flang/parser/dump-parse-tree.h index aca18137f955..a6181834c94f 100644 --- a/include/flang/parser/dump-parse-tree.h +++ b/include/flang/parser/dump-parse-tree.h @@ -40,11 +40,11 @@ class ParseTreeDumper { std::ostream &out, const AnalyzedObjectsAsFortran *asFortran = nullptr) : out_(out), asFortran_{asFortran} {} - constexpr const char *GetNodeName(const char *) { return "char *"; } + static constexpr const char *GetNodeName(const char *) { return "char *"; } #define NODE_NAME(T, N) \ - constexpr const char *GetNodeName(const T &) { return N; } + static constexpr const char *GetNodeName(const T &) { return N; } #define NODE_ENUM(T, E) \ - std::string GetNodeName(const T::E &x) { \ + static std::string GetNodeName(const T::E &x) { \ return #E " = "s + T::EnumToString(x); \ } #define NODE(T1, T2) NODE_NAME(T1::T2, #T2) diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index ead8243ccedd..e187f483a8fa 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "flang/lower/ASTBuilder.h" +#include "flang/parser/dump-parse-tree.h" #include "flang/parser/parse-tree-visitor.h" #include #include @@ -195,14 +196,14 @@ class ASTBuilder { void Post(const Pa::UnlabeledStatement &s) { addEval(std::visit( [&](const auto &x) { - return AST::Evaluation{x, s.source, {}, parents.back()}; + return AST::Evaluation{x, parents.back(), s.source, {}}; }, s.statement.u)); } void Post(const Pa::Statement &s) { addEval(std::visit( [&](const auto &x) { - return AST::Evaluation{x, s.source, s.label, parents.back()}; + return AST::Evaluation{x, parents.back(), s.source, s.label}; }, s.statement.u)); } @@ -249,14 +250,14 @@ class ASTBuilder { return std::visit( Co::visitors{ [&](const Pa::ContinueStmt &x) { - return AST::Evaluation{x, s.source, s.label, parents.back()}; + return AST::Evaluation{x, parents.back(), s.source, s.label}; }, [&](const Pa::FailImageStmt &x) { - return AST::Evaluation{x, s.source, s.label, parents.back()}; + return AST::Evaluation{x, parents.back(), s.source, s.label}; }, [&](const auto &x) { - return AST::Evaluation{x.value(), s.source, s.label, - parents.back()}; + return AST::Evaluation{x.value(), parents.back(), s.source, + s.label}; }, }, s.statement.u); @@ -266,13 +267,13 @@ class ASTBuilder { return std::visit( Co::visitors{ [&](const Pa::ContinueStmt &x) { - return AST::Evaluation{x, s.source, {}, parents.back()}; + return AST::Evaluation{x, parents.back(), s.source, {}}; }, [&](const Pa::FailImageStmt &x) { - return AST::Evaluation{x, s.source, {}, parents.back()}; + return AST::Evaluation{x, parents.back(), s.source, {}}; }, [&](const auto &x) { - return AST::Evaluation{x.value(), s.source, {}, parents.back()}; + return AST::Evaluation{x.value(), parents.back(), s.source, {}}; }, }, s.statement.u); @@ -280,13 +281,13 @@ class ASTBuilder { template AST::Evaluation makeEvalIndirect(const Pa::Statement> &s) { - return AST::Evaluation{s.statement.value(), s.source, s.label, - parents.back()}; + return AST::Evaluation{s.statement.value(), parents.back(), s.source, + s.label}; } template AST::Evaluation makeEvalDirect(const Pa::Statement &s) { - return AST::Evaluation{s.statement, s.source, s.label, parents.back()}; + return AST::Evaluation{s.statement, parents.back(), s.source, s.label}; } // When we enter a function-like structure, we want to build a new unit and @@ -613,101 +614,11 @@ inline void annotateFuncCFG(AST::FunctionLikeUnit &flu) { L::StringRef evalName(AST::Evaluation &e) { return std::visit( - Co::visitors{ - [](const Pa::AllocateStmt *) { return "AllocateStmt"; }, - [](const Pa::ArithmeticIfStmt *) { return "ArithmeticIfStmt"; }, - [](const Pa::AssignedGotoStmt *) { return "AssignedGotoStmt"; }, - [](const Pa::AssignmentStmt *) { return "AssignmentStmt"; }, - [](const Pa::AssignStmt *) { return "AssignStmt"; }, - [](const Pa::BackspaceStmt *) { return "BackspaceStmt"; }, - [](const Pa::CallStmt *) { return "CallStmt"; }, - [](const Pa::CloseStmt *) { return "CloseStmt"; }, - [](const Pa::ComputedGotoStmt *) { return "ComputedGotoStmt"; }, - [](const Pa::ContinueStmt *) { return "ContinueStmt"; }, - [](const Pa::CycleStmt *) { return "CycleStmt"; }, - [](const Pa::DeallocateStmt *) { return "DeallocateStmt"; }, - [](const Pa::EndfileStmt *) { return "EndfileStmt"; }, - [](const Pa::EventPostStmt *) { return "EventPostStmt"; }, - [](const Pa::EventWaitStmt *) { return "EventWaitStmt"; }, - [](const Pa::ExitStmt *) { return "ExitStmt"; }, - [](const Pa::FailImageStmt *) { return "FailImageStmt"; }, - [](const Pa::FlushStmt *) { return "FlushStmt"; }, - [](const Pa::ForallStmt *) { return "ForallStmt"; }, - [](const Pa::FormTeamStmt *) { return "FormTeamStmt"; }, - [](const Pa::GotoStmt *) { return "GotoStmt"; }, - [](const Pa::IfStmt *) { return "IfStmt"; }, - [](const Pa::InquireStmt *) { return "InquireStmt"; }, - [](const Pa::LockStmt *) { return "LockStmt"; }, - [](const Pa::NullifyStmt *) { return "NullifyStmt"; }, - [](const Pa::OpenStmt *) { return "OpenStmt"; }, - [](const Pa::PauseStmt *) { return "PauseStmt"; }, - [](const Pa::PointerAssignmentStmt *) { - return "PointerAssignmentStmt"; - }, - [](const Pa::PrintStmt *) { return "PrintStmt"; }, - [](const Pa::ReadStmt *) { return "ReadStmt"; }, - [](const Pa::ReturnStmt *) { return "ReturnStmt"; }, - [](const Pa::RewindStmt *) { return "RewindStmt"; }, - [](const Pa::StopStmt *) { return "StopStmt"; }, - [](const Pa::SyncAllStmt *) { return "SyncAllStmt"; }, - [](const Pa::SyncImagesStmt *) { return "SyncImagesStmt"; }, - [](const Pa::SyncMemoryStmt *) { return "SyncMemoryStmt"; }, - [](const Pa::SyncTeamStmt *) { return "SyncTeamStmt"; }, - [](const Pa::UnlockStmt *) { return "UnlockStmt"; }, - [](const Pa::WaitStmt *) { return "WaitStmt"; }, - [](const Pa::WhereStmt *) { return "WhereStmt"; }, - [](const Pa::WriteStmt *) { return "WriteStmt"; }, - - [](const AST::CGJump) { return "CGJump"; }, - - [](const Pa::DataStmt *) { return "DataStmt"; }, - [](const Pa::EntryStmt *) { return "EntryStmt"; }, - [](const Pa::FormatStmt *) { return "FormatStmt"; }, - [](const Pa::NamelistStmt *) { return "NamelistStmt"; }, - - [](const Pa::AssociateConstruct *) { return "AssociateConstruct"; }, - [](const Pa::BlockConstruct *) { return "BlockConstruct"; }, - [](const Pa::CaseConstruct *) { return "CaseConstruct"; }, - [](const Pa::ChangeTeamConstruct *) { return "ChangeTeamConstruct"; }, - [](const Pa::CompilerDirective *) { return "CompilerDirective"; }, - [](const Pa::CriticalConstruct *) { return "CriticalConstruct"; }, - [](const Pa::DoConstruct *) { return "DoConstruct"; }, - [](const Pa::ForallConstruct *) { return "ForallConstruct"; }, - [](const Pa::IfConstruct *) { return "IfConstruct"; }, - [](const Pa::OmpEndLoopDirective *) { return "OmpEndLoopDirective"; }, - [](const Pa::OpenMPConstruct *) { return "OpenMPConstruct"; }, - [](const Pa::SelectRankConstruct *) { return "SelectRankConstruct"; }, - [](const Pa::SelectTypeConstruct *) { return "SelectTypeConstruct"; }, - [](const Pa::WhereConstruct *) { return "WhereConstruct"; }, - - [](const Pa::AssociateStmt *) { return "AssociateStmt"; }, - [](const Pa::BlockStmt *) { return "BlockStmt"; }, - [](const Pa::CaseStmt *) { return "CaseStmt"; }, - [](const Pa::ChangeTeamStmt *) { return "ChangeTeamStmt"; }, - [](const Pa::CriticalStmt *) { return "CriticalStmt"; }, - [](const Pa::ElseIfStmt *) { return "ElseIfStmt"; }, - [](const Pa::ElseStmt *) { return "ElseStmt"; }, - [](const Pa::ElsewhereStmt *) { return "ElsewhereStmt"; }, - [](const Pa::EndAssociateStmt *) { return "EndAssociateStmt"; }, - [](const Pa::EndBlockStmt *) { return "EndBlockStmt"; }, - [](const Pa::EndChangeTeamStmt *) { return "EndChangeTeamStmt"; }, - [](const Pa::EndCriticalStmt *) { return "EndCriticalStmt"; }, - [](const Pa::EndDoStmt *) { return "EndDoStmt"; }, - [](const Pa::EndForallStmt *) { return "EndForallStmt"; }, - [](const Pa::EndIfStmt *) { return "EndIfStmt"; }, - [](const Pa::EndSelectStmt *) { return "EndSelectStmt"; }, - [](const Pa::EndWhereStmt *) { return "EndWhereStmt"; }, - [](const Pa::ForallConstructStmt *) { return "ForallConstructStmt"; }, - [](const Pa::IfThenStmt *) { return "IfThenStmt"; }, - [](const Pa::MaskedElsewhereStmt *) { return "MaskedElsewhereStmt"; }, - [](const Pa::NonLabelDoStmt *) { return "NonLabelDoStmt"; }, - [](const Pa::SelectCaseStmt *) { return "SelectCaseStmt"; }, - [](const Pa::SelectRankCaseStmt *) { return "SelectRankCaseStmt"; }, - [](const Pa::SelectRankStmt *) { return "SelectRankStmt"; }, - [](const Pa::SelectTypeStmt *) { return "SelectTypeStmt"; }, - [](const Pa::TypeGuardStmt *) { return "TypeGuardStmt"; }, - [](const Pa::WhereConstructStmt *) { return "WhereConstructStmt"; }, - }, + Co::visitors{[](const AST::CGJump) { return "CGJump"; }, + [](const auto *parseTreeNode) { + assert(parseTreeNode && "nullptr node in AST "); + return Pa::ParseTreeDumper::GetNodeName(*parseTreeNode); + }}, e.u); } @@ -819,9 +730,9 @@ Br::AST::ModuleLikeUnit::ModuleLikeUnit(const Pa::Submodule &m, modStmts.push_back(&std::get>(m.t)); } -Br::AST::BlockDataUnit::BlockDataUnit(const Pa::BlockData &db, +Br::AST::BlockDataUnit::BlockDataUnit(const Pa::BlockData &bd, const AST::ParentType &parent) - : ProgramUnit{&db, parent} {} + : ProgramUnit{&bd, parent} {} AST::Program *Br::createAST(const Pa::Program &root) { ASTBuilder walker; From 5bb28e34d8b27995fc72ab7c186a8188f089dc06 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 29 Jan 2020 17:33:29 -0800 Subject: [PATCH 05/24] [review 959] "improved readability" --- include/flang/lower/ASTBuilder.h | 255 ++++---- lib/lower/ASTBuilder.cpp | 1015 ++++++++++++++++++------------ 2 files changed, 740 insertions(+), 530 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 00ec879185d0..4cc496a8cc14 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -21,6 +21,11 @@ struct Program; struct ModuleLikeUnit; struct FunctionLikeUnit; +// TODO: A collection of Evaluations can obviously be any of the container +// types; leaving this as a std::list _for now_ because we reserve the right to +// insert AST nodes in any order in O(1) time. +using EvaluationCollection = std::list; + using ParentType = std::variant; @@ -49,20 +54,20 @@ struct CGJump { /// is `A` a construct (or directive)? template constexpr static bool isConstruct() { - return std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; + return std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; } /// Function-like units can contains lists of evaluations. These can be @@ -71,63 +76,88 @@ constexpr static bool isConstruct() { struct Evaluation { using EvalVariant = std::variant< // action statements - const parser::AllocateStmt *, const parser::AssignmentStmt *, - const parser::BackspaceStmt *, const parser::CallStmt *, - const parser::CloseStmt *, const parser::ContinueStmt *, - const parser::CycleStmt *, const parser::DeallocateStmt *, - const parser::EndfileStmt *, const parser::EventPostStmt *, - const parser::EventWaitStmt *, const parser::ExitStmt *, - const parser::FailImageStmt *, const parser::FlushStmt *, - const parser::FormTeamStmt *, const parser::GotoStmt *, - const parser::IfStmt *, const parser::InquireStmt *, - const parser::LockStmt *, const parser::NullifyStmt *, - const parser::OpenStmt *, const parser::PointerAssignmentStmt *, - const parser::PrintStmt *, const parser::ReadStmt *, - const parser::ReturnStmt *, const parser::RewindStmt *, - const parser::StopStmt *, const parser::SyncAllStmt *, - const parser::SyncImagesStmt *, const parser::SyncMemoryStmt *, - const parser::SyncTeamStmt *, const parser::UnlockStmt *, - const parser::WaitStmt *, const parser::WhereStmt *, - const parser::WriteStmt *, const parser::ComputedGotoStmt *, - const parser::ForallStmt *, const parser::ArithmeticIfStmt *, - const parser::AssignStmt *, const parser::AssignedGotoStmt *, - const parser::PauseStmt *, + const Fortran::parser::AllocateStmt *, + const Fortran::parser::AssignmentStmt *, + const Fortran::parser::BackspaceStmt *, const Fortran::parser::CallStmt *, + const Fortran::parser::CloseStmt *, const Fortran::parser::ContinueStmt *, + const Fortran::parser::CycleStmt *, + const Fortran::parser::DeallocateStmt *, + const Fortran::parser::EndfileStmt *, + const Fortran::parser::EventPostStmt *, + const Fortran::parser::EventWaitStmt *, const Fortran::parser::ExitStmt *, + const Fortran::parser::FailImageStmt *, + const Fortran::parser::FlushStmt *, const Fortran::parser::FormTeamStmt *, + const Fortran::parser::GotoStmt *, const Fortran::parser::IfStmt *, + const Fortran::parser::InquireStmt *, const Fortran::parser::LockStmt *, + const Fortran::parser::NullifyStmt *, const Fortran::parser::OpenStmt *, + const Fortran::parser::PointerAssignmentStmt *, + const Fortran::parser::PrintStmt *, const Fortran::parser::ReadStmt *, + const Fortran::parser::ReturnStmt *, const Fortran::parser::RewindStmt *, + const Fortran::parser::StopStmt *, const Fortran::parser::SyncAllStmt *, + const Fortran::parser::SyncImagesStmt *, + const Fortran::parser::SyncMemoryStmt *, + const Fortran::parser::SyncTeamStmt *, + const Fortran::parser::UnlockStmt *, const Fortran::parser::WaitStmt *, + const Fortran::parser::WhereStmt *, const Fortran::parser::WriteStmt *, + const Fortran::parser::ComputedGotoStmt *, + const Fortran::parser::ForallStmt *, + const Fortran::parser::ArithmeticIfStmt *, + const Fortran::parser::AssignStmt *, + const Fortran::parser::AssignedGotoStmt *, + const Fortran::parser::PauseStmt *, // compiler generated ops CGJump, // other statements - const parser::FormatStmt *, const parser::EntryStmt *, - const parser::DataStmt *, const parser::NamelistStmt *, + const Fortran::parser::FormatStmt *, const Fortran::parser::EntryStmt *, + const Fortran::parser::DataStmt *, const Fortran::parser::NamelistStmt *, // constructs - const parser::AssociateConstruct *, const parser::BlockConstruct *, - const parser::CaseConstruct *, const parser::ChangeTeamConstruct *, - const parser::CriticalConstruct *, const parser::DoConstruct *, - const parser::IfConstruct *, const parser::SelectRankConstruct *, - const parser::SelectTypeConstruct *, const parser::WhereConstruct *, - const parser::ForallConstruct *, const parser::CompilerDirective *, - const parser::OpenMPConstruct *, const parser::OmpEndLoopDirective *, + const Fortran::parser::AssociateConstruct *, + const Fortran::parser::BlockConstruct *, + const Fortran::parser::CaseConstruct *, + const Fortran::parser::ChangeTeamConstruct *, + const Fortran::parser::CriticalConstruct *, + const Fortran::parser::DoConstruct *, + const Fortran::parser::IfConstruct *, + const Fortran::parser::SelectRankConstruct *, + const Fortran::parser::SelectTypeConstruct *, + const Fortran::parser::WhereConstruct *, + const Fortran::parser::ForallConstruct *, + const Fortran::parser::CompilerDirective *, + const Fortran::parser::OpenMPConstruct *, + const Fortran::parser::OmpEndLoopDirective *, // construct statements - const parser::AssociateStmt *, const parser::EndAssociateStmt *, - const parser::BlockStmt *, const parser::EndBlockStmt *, - const parser::SelectCaseStmt *, const parser::CaseStmt *, - const parser::EndSelectStmt *, const parser::ChangeTeamStmt *, - const parser::EndChangeTeamStmt *, const parser::CriticalStmt *, - const parser::EndCriticalStmt *, const parser::NonLabelDoStmt *, - const parser::EndDoStmt *, const parser::IfThenStmt *, - const parser::ElseIfStmt *, const parser::ElseStmt *, - const parser::EndIfStmt *, const parser::SelectRankStmt *, - const parser::SelectRankCaseStmt *, const parser::SelectTypeStmt *, - const parser::TypeGuardStmt *, const parser::WhereConstructStmt *, - const parser::MaskedElsewhereStmt *, const parser::ElsewhereStmt *, - const parser::EndWhereStmt *, const parser::ForallConstructStmt *, - const parser::EndForallStmt *>; + const Fortran::parser::AssociateStmt *, + const Fortran::parser::EndAssociateStmt *, + const Fortran::parser::BlockStmt *, const Fortran::parser::EndBlockStmt *, + const Fortran::parser::SelectCaseStmt *, + const Fortran::parser::CaseStmt *, const Fortran::parser::EndSelectStmt *, + const Fortran::parser::ChangeTeamStmt *, + const Fortran::parser::EndChangeTeamStmt *, + const Fortran::parser::CriticalStmt *, + const Fortran::parser::EndCriticalStmt *, + const Fortran::parser::NonLabelDoStmt *, + const Fortran::parser::EndDoStmt *, const Fortran::parser::IfThenStmt *, + const Fortran::parser::ElseIfStmt *, const Fortran::parser::ElseStmt *, + const Fortran::parser::EndIfStmt *, + const Fortran::parser::SelectRankStmt *, + const Fortran::parser::SelectRankCaseStmt *, + const Fortran::parser::SelectTypeStmt *, + const Fortran::parser::TypeGuardStmt *, + const Fortran::parser::WhereConstructStmt *, + const Fortran::parser::MaskedElsewhereStmt *, + const Fortran::parser::ElsewhereStmt *, + const Fortran::parser::EndWhereStmt *, + const Fortran::parser::ForallConstructStmt *, + const Fortran::parser::EndForallStmt *>; Evaluation() = delete; Evaluation(const Evaluation &) = default; /// General ctor template - Evaluation(const A &a, const ParentType &p, const parser::CharBlock &pos, - const std::optional &lab) + Evaluation(const A &a, const ParentType &p, + const Fortran::parser::CharBlock &pos, + const std::optional &lab) : u{&a}, parent{p}, pos{pos}, lab{lab} {} /// Compiler-generated jump @@ -155,10 +185,10 @@ struct Evaluation { /// is `A` not an executable statement? template constexpr static bool isOther(const A &) { - return std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; + return std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; } constexpr bool isActionStmt() const { @@ -194,22 +224,21 @@ struct Evaluation { /// control flow void setBranches() { containsBranches = true; } - constexpr std::list *getConstructEvals() { + constexpr EvaluationCollection *getConstructEvals() { return isStmt() ? nullptr : subs; } /// Set that the construct `cstr` (if not a nullptr) has branches. static void setBranches(Evaluation *cstr) { - if (cstr) { + if (cstr) cstr->setBranches(); - } } EvalVariant u; ParentType parent; - parser::CharBlock pos; - std::optional lab; - std::list *subs{nullptr}; // construct sub-statements + Fortran::parser::CharBlock pos; + std::optional lab; + EvaluationCollection *subs; // construct sub-statements CFGAnnotation cfg{CFGAnnotation::None}; bool isTarget{false}; // this evaluation is a control target bool containsBranches{false}; // construct contains branches @@ -221,11 +250,13 @@ struct ProgramUnit { template ProgramUnit(A *ptr, const ParentType &parent) : p{ptr}, parent{parent} {} - std::variant + std::variant p; ParentType parent; }; @@ -234,49 +265,51 @@ struct ProgramUnit { /// statements. struct FunctionLikeUnit : public ProgramUnit { // wrapper statements for function-like syntactic structures - using FunctionStatement = - std::variant *, - const parser::Statement *, - const parser::Statement *, - const parser::Statement *, - const parser::Statement *, - const parser::Statement *, - const parser::Statement *, - const parser::Statement *>; - - FunctionLikeUnit(const parser::MainProgram &f, const ParentType &parent); - FunctionLikeUnit(const parser::FunctionSubprogram &f, + using FunctionStatement = std::variant< + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *>; + + FunctionLikeUnit(const Fortran::parser::MainProgram &f, + const ParentType &parent); + FunctionLikeUnit(const Fortran::parser::FunctionSubprogram &f, const ParentType &parent); - FunctionLikeUnit(const parser::SubroutineSubprogram &f, + FunctionLikeUnit(const Fortran::parser::SubroutineSubprogram &f, const ParentType &parent); - FunctionLikeUnit(const parser::SeparateModuleSubprogram &f, + FunctionLikeUnit(const Fortran::parser::SeparateModuleSubprogram &f, const ParentType &parent); bool isMainProgram() { - return std::get_if *>( - &funStmts.back()); + return std::holds_alternative< + const Fortran::parser::Statement *>( + funStmts.back()); } - const parser::FunctionStmt *isFunction() { - return isA(); + const Fortran::parser::FunctionStmt *getFunction() { + return getA(); } - const parser::SubroutineStmt *isSubroutine() { - return isA(); + const Fortran::parser::SubroutineStmt *getSubroutine() { + return getA(); } - const parser::MpSubprogramStmt *isMPSubp() { - return isA(); + const Fortran::parser::MpSubprogramStmt *getMPSubp() { + return getA(); } const semantics::Scope *scope{nullptr}; // scope from front-end std::list funStmts; // begin/end pair - std::list evals; // statements + EvaluationCollection evals; // statements std::list funcs; // internal procedures private: template - const A *isA() { - if (auto p = std::get_if *>(&funStmts.front())) { + const A *getA() { + if (auto p = std::get_if *>( + &funStmts.front())) return &(*p)->statement; - } return nullptr; } }; @@ -285,14 +318,14 @@ struct FunctionLikeUnit : public ProgramUnit { /// function-like units. struct ModuleLikeUnit : public ProgramUnit { // wrapper statements for module-like syntactic structures - using ModuleStatement = - std::variant *, - const parser::Statement *, - const parser::Statement *, - const parser::Statement *>; - - ModuleLikeUnit(const parser::Module &m, const ParentType &parent); - ModuleLikeUnit(const parser::Submodule &m, const ParentType &parent); + using ModuleStatement = std::variant< + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *, + const Fortran::parser::Statement *>; + + ModuleLikeUnit(const Fortran::parser::Module &m, const ParentType &parent); + ModuleLikeUnit(const Fortran::parser::Submodule &m, const ParentType &parent); ~ModuleLikeUnit() = default; const semantics::Scope *scope{nullptr}; @@ -301,7 +334,7 @@ struct ModuleLikeUnit : public ProgramUnit { }; struct BlockDataUnit : public ProgramUnit { - BlockDataUnit(const parser::BlockData &bd, const ParentType &parent); + BlockDataUnit(const Fortran::parser::BlockData &bd, const ParentType &parent); }; /// A Program is the top-level AST @@ -317,7 +350,7 @@ struct Program { } // namespace AST /// Create an AST from the parse tree -AST::Program *createAST(const parser::Program &root); +AST::Program *createAST(const Fortran::parser::Program &root); /// Decorate the AST with control flow annotations /// diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index e187f483a8fa..5b3f728b77ee 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -22,14 +22,6 @@ /// are either statements or constructs, where a construct contains a list of /// evaluations. The resulting AST structure can then be used to create FIR. -namespace Br = Fortran::lower; -namespace Co = Fortran::common; -namespace L = llvm; -namespace Pa = Fortran::parser; - -using namespace Fortran; -using namespace Br; - namespace { /// The instantiation of a parse tree visitor (Pre and Post) is extremely @@ -38,12 +30,12 @@ namespace { class ASTBuilder { public: ASTBuilder() { - pgm = new AST::Program; + pgm = new Fortran::lower::AST::Program; parents.push_back(pgm); } /// Get the result - AST::Program *result() { return pgm; } + Fortran::lower::AST::Program *result() { return pgm; } template constexpr bool Pre(const A &) { @@ -54,28 +46,34 @@ class ASTBuilder { // Module like - bool Pre(const Pa::Module &x) { return enterModule(x); } - bool Pre(const Pa::Submodule &x) { return enterModule(x); } + bool Pre(const Fortran::parser::Module &node) { return enterModule(node); } + bool Pre(const Fortran::parser::Submodule &node) { return enterModule(node); } - void Post(const Pa::Module &) { exitModule(); } - void Post(const Pa::Submodule &) { exitModule(); } + void Post(const Fortran::parser::Module &) { exitModule(); } + void Post(const Fortran::parser::Submodule &) { exitModule(); } // Function like - bool Pre(const Pa::MainProgram &x) { return enterFunc(x); } - bool Pre(const Pa::FunctionSubprogram &x) { return enterFunc(x); } - bool Pre(const Pa::SubroutineSubprogram &x) { return enterFunc(x); } - bool Pre(const Pa::SeparateModuleSubprogram &x) { return enterFunc(x); } + bool Pre(const Fortran::parser::MainProgram &node) { return enterFunc(node); } + bool Pre(const Fortran::parser::FunctionSubprogram &node) { + return enterFunc(node); + } + bool Pre(const Fortran::parser::SubroutineSubprogram &node) { + return enterFunc(node); + } + bool Pre(const Fortran::parser::SeparateModuleSubprogram &node) { + return enterFunc(node); + } - void Post(const Pa::MainProgram &) { exitFunc(); } - void Post(const Pa::FunctionSubprogram &) { exitFunc(); } - void Post(const Pa::SubroutineSubprogram &) { exitFunc(); } - void Post(const Pa::SeparateModuleSubprogram &) { exitFunc(); } + void Post(const Fortran::parser::MainProgram &) { exitFunc(); } + void Post(const Fortran::parser::FunctionSubprogram &) { exitFunc(); } + void Post(const Fortran::parser::SubroutineSubprogram &) { exitFunc(); } + void Post(const Fortran::parser::SeparateModuleSubprogram &) { exitFunc(); } // Block data - void Post(const Pa::BlockData &x) { - AST::BlockDataUnit unit{x, parents.back()}; + void Post(const Fortran::parser::BlockData &node) { + Fortran::lower::AST::BlockDataUnit unit{node, parents.back()}; addUnit(unit); } @@ -83,10 +81,12 @@ class ASTBuilder { // Action statements // - void Post(const Pa::Statement &s) { + void Post(const Fortran::parser::Statement &s) { addEval(makeEvalAction(s)); } - void Post(const Pa::UnlabeledStatement &s) { + void + Post(const Fortran::parser::UnlabeledStatement + &s) { addEval(makeEvalAction(s)); } @@ -94,207 +94,292 @@ class ASTBuilder { // Non-executable statements // - void Post(const Pa::Statement> &s) { - addEval(makeEvalIndirect(s)); + void + Post(const Fortran::parser::Statement< + Fortran::common::Indirection> &statement) { + addEval(makeEvalIndirect(statement)); } - void Post(const Pa::Statement> &s) { - addEval(makeEvalIndirect(s)); + void + Post(const Fortran::parser::Statement< + Fortran::common::Indirection> &statement) { + addEval(makeEvalIndirect(statement)); } - void Post(const Pa::Statement> &s) { - addEval(makeEvalIndirect(s)); + void + Post(const Fortran::parser::Statement< + Fortran::common::Indirection> &statement) { + addEval(makeEvalIndirect(statement)); } - void Post(const Pa::Statement> &s) { - addEval(makeEvalIndirect(s)); + void Post(const Fortran::parser::Statement> &statement) { + addEval(makeEvalIndirect(statement)); } // // Construct statements // - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post( + const Fortran::parser::Statement &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void + Post(const Fortran::parser::Statement &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post( + const Fortran::parser::Statement &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void + Post(const Fortran::parser::Statement &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post( + const Fortran::parser::Statement &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void + Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void + Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void + Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void + Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } - void Post(const Pa::Statement &s) { - addEval(makeEvalDirect(s)); + void Post(const Fortran::parser::Statement + &statement) { + addEval(makeEvalDirect(statement)); } // Get rid of production wrapper - void Post(const Pa::UnlabeledStatement &s) { + void Post(const Fortran::parser::UnlabeledStatement< + Fortran::parser::ForallAssignmentStmt> &statement) { addEval(std::visit( [&](const auto &x) { - return AST::Evaluation{x, parents.back(), s.source, {}}; + return Fortran::lower::AST::Evaluation{ + x, parents.back(), statement.source, {}}; }, - s.statement.u)); + statement.statement.u)); } - void Post(const Pa::Statement &s) { + void + Post(const Fortran::parser::Statement + &statement) { addEval(std::visit( [&](const auto &x) { - return AST::Evaluation{x, parents.back(), s.source, s.label}; + return Fortran::lower::AST::Evaluation{ + x, parents.back(), statement.source, statement.label}; }, - s.statement.u)); + statement.statement.u)); } // // Constructs (enter and exit) // - bool Pre(const Pa::AssociateConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::BlockConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::CaseConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::ChangeTeamConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::CriticalConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::DoConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::IfConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::SelectRankConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::SelectTypeConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::WhereConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::ForallConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::CompilerDirective &c) { return enterConstruct(c); } - bool Pre(const Pa::OpenMPConstruct &c) { return enterConstruct(c); } - bool Pre(const Pa::OmpEndLoopDirective &c) { return enterConstruct(c); } - - void Post(const Pa::AssociateConstruct &) { exitConstruct(); } - void Post(const Pa::BlockConstruct &) { exitConstruct(); } - void Post(const Pa::CaseConstruct &) { exitConstruct(); } - void Post(const Pa::ChangeTeamConstruct &) { exitConstruct(); } - void Post(const Pa::CriticalConstruct &) { exitConstruct(); } - void Post(const Pa::DoConstruct &) { exitConstruct(); } - void Post(const Pa::IfConstruct &) { exitConstruct(); } - void Post(const Pa::SelectRankConstruct &) { exitConstruct(); } - void Post(const Pa::SelectTypeConstruct &) { exitConstruct(); } - void Post(const Pa::WhereConstruct &) { exitConstruct(); } - void Post(const Pa::ForallConstruct &) { exitConstruct(); } - void Post(const Pa::CompilerDirective &) { exitConstruct(); } - void Post(const Pa::OpenMPConstruct &) { exitConstruct(); } - void Post(const Pa::OmpEndLoopDirective &) { exitConstruct(); } + bool Pre(const Fortran::parser::AssociateConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::BlockConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::CaseConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::ChangeTeamConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::CriticalConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::DoConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::IfConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::SelectRankConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::SelectTypeConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::WhereConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::ForallConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::CompilerDirective &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::OpenMPConstruct &construct) { + return enterConstruct(construct); + } + bool Pre(const Fortran::parser::OmpEndLoopDirective &construct) { + return enterConstruct(construct); + } + + void Post(const Fortran::parser::AssociateConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::BlockConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::CaseConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::ChangeTeamConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::CriticalConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::DoConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::IfConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::SelectRankConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::SelectTypeConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::WhereConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::ForallConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::CompilerDirective &) { exitConstruct(); } + void Post(const Fortran::parser::OpenMPConstruct &) { exitConstruct(); } + void Post(const Fortran::parser::OmpEndLoopDirective &) { exitConstruct(); } private: // ActionStmt has a couple of non-conforming cases, which get handled // explicitly here. The other cases use an Indirection, which we discard in // the AST. - AST::Evaluation makeEvalAction(const Pa::Statement &s) { + Fortran::lower::AST::Evaluation + makeEvalAction(const Fortran::parser::Statement + &statement) { return std::visit( - Co::visitors{ - [&](const Pa::ContinueStmt &x) { - return AST::Evaluation{x, parents.back(), s.source, s.label}; + Fortran::common::visitors{ + [&](const Fortran::parser::ContinueStmt &x) { + return Fortran::lower::AST::Evaluation{ + x, parents.back(), statement.source, statement.label}; }, - [&](const Pa::FailImageStmt &x) { - return AST::Evaluation{x, parents.back(), s.source, s.label}; + [&](const Fortran::parser::FailImageStmt &x) { + return Fortran::lower::AST::Evaluation{ + x, parents.back(), statement.source, statement.label}; }, [&](const auto &x) { - return AST::Evaluation{x.value(), parents.back(), s.source, - s.label}; + return Fortran::lower::AST::Evaluation{ + x.value(), parents.back(), statement.source, statement.label}; }, }, - s.statement.u); + statement.statement.u); } - AST::Evaluation - makeEvalAction(const Pa::UnlabeledStatement &s) { + Fortran::lower::AST::Evaluation makeEvalAction( + const Fortran::parser::UnlabeledStatement + &statement) { return std::visit( - Co::visitors{ - [&](const Pa::ContinueStmt &x) { - return AST::Evaluation{x, parents.back(), s.source, {}}; + Fortran::common::visitors{ + [&](const Fortran::parser::ContinueStmt &x) { + return Fortran::lower::AST::Evaluation{ + x, parents.back(), statement.source, {}}; }, - [&](const Pa::FailImageStmt &x) { - return AST::Evaluation{x, parents.back(), s.source, {}}; + [&](const Fortran::parser::FailImageStmt &x) { + return Fortran::lower::AST::Evaluation{ + x, parents.back(), statement.source, {}}; }, [&](const auto &x) { - return AST::Evaluation{x.value(), parents.back(), s.source, {}}; + return Fortran::lower::AST::Evaluation{ + x.value(), parents.back(), statement.source, {}}; }, }, - s.statement.u); + statement.statement.u); } template - AST::Evaluation makeEvalIndirect(const Pa::Statement> &s) { - return AST::Evaluation{s.statement.value(), parents.back(), s.source, - s.label}; + Fortran::lower::AST::Evaluation makeEvalIndirect( + const Fortran::parser::Statement> + &statement) { + return Fortran::lower::AST::Evaluation{statement.statement.value(), + parents.back(), statement.source, + statement.label}; } template - AST::Evaluation makeEvalDirect(const Pa::Statement &s) { - return AST::Evaluation{s.statement, parents.back(), s.source, s.label}; + Fortran::lower::AST::Evaluation + makeEvalDirect(const Fortran::parser::Statement &statement) { + return Fortran::lower::AST::Evaluation{statement.statement, parents.back(), + statement.source, statement.label}; } // When we enter a function-like structure, we want to build a new unit and // set the builder's cursors to point to it. template - bool enterFunc(const A &f) { - auto &unit = addFunc(AST::FunctionLikeUnit{f, parents.back()}); + bool enterFunc(const A &func) { + auto &unit = + addFunc(Fortran::lower::AST::FunctionLikeUnit{func, parents.back()}); funclist = &unit.funcs; pushEval(&unit.evals); parents.emplace_back(&unit); @@ -310,9 +395,10 @@ class ASTBuilder { // When we enter a construct structure, we want to build a new construct and // set the builder's evaluation cursor to point to it. template - bool enterConstruct(const A &c) { - auto &con = addEval(AST::Evaluation{c, parents.back()}); - con.subs = new std::list(); + bool enterConstruct(const A &construct) { + auto &con = + addEval(Fortran::lower::AST::Evaluation{construct, parents.back()}); + con.subs = new Fortran::lower::AST::EvaluationCollection; pushEval(con.subs); parents.emplace_back(&con); return true; @@ -326,8 +412,9 @@ class ASTBuilder { // When we enter a module structure, we want to build a new module and // set the builder's function cursor to point to it. template - bool enterModule(const A &f) { - auto &unit = addUnit(AST::ModuleLikeUnit{f, parents.back()}); + bool enterModule(const A &func) { + auto &unit = + addUnit(Fortran::lower::AST::ModuleLikeUnit{func, parents.back()}); funclist = &unit.funcs; parents.emplace_back(&unit); return true; @@ -354,7 +441,8 @@ class ASTBuilder { } /// move the Evaluation to the end of the current list - AST::Evaluation &addEval(AST::Evaluation &&eval) { + Fortran::lower::AST::Evaluation & + addEval(Fortran::lower::AST::Evaluation &&eval) { assert(funclist && "not in a function"); assert(evallist.size() > 0); evallist.back()->emplace_back(std::move(eval)); @@ -362,7 +450,7 @@ class ASTBuilder { } /// push a new list on the stack of Evaluation lists - void pushEval(std::list *eval) { + void pushEval(Fortran::lower::AST::EvaluationCollection *eval) { assert(funclist && "not in a function"); assert(eval && eval->empty() && "evaluation list isn't correct"); evallist.emplace_back(eval); @@ -374,40 +462,38 @@ class ASTBuilder { evallist.pop_back(); } - AST::Program *pgm; - std::list *funclist{nullptr}; - std::vector *> evallist; - std::vector parents; + Fortran::lower::AST::Program *pgm; + std::list *funclist{nullptr}; + std::vector evallist; + std::vector parents; }; template constexpr bool hasErrLabel(const A &stmt) { - if constexpr (std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v) { for (const auto &control : stmt.controls) { - if (std::holds_alternative(control.u)) { + if (std::holds_alternative(control.u)) return true; - } } } - if constexpr (std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v) { for (const auto &spec : stmt.v) { - if (std::holds_alternative(spec.u)) { + if (std::holds_alternative(spec.u)) return true; - } } } - if constexpr (std::is_same_v) { - for (const auto &spec : std::get>(stmt.u)) { - if (std::holds_alternative(spec.u)) { + if constexpr (std::is_same_v) { + for (const auto &spec : + std::get>(stmt.u)) { + if (std::holds_alternative(spec.u)) return true; - } } } return false; @@ -415,19 +501,17 @@ constexpr bool hasErrLabel(const A &stmt) { template constexpr bool hasEorLabel(const A &stmt) { - if constexpr (std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v) { for (const auto &control : stmt.controls) { - if (std::holds_alternative(control.u)) { + if (std::holds_alternative(control.u)) return true; - } } } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { for (const auto &waitSpec : stmt.v) { - if (std::holds_alternative(waitSpec.u)) { + if (std::holds_alternative(waitSpec.u)) return true; - } } } return false; @@ -435,324 +519,415 @@ constexpr bool hasEorLabel(const A &stmt) { template constexpr bool hasEndLabel(const A &stmt) { - if constexpr (std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v) { for (const auto &control : stmt.controls) { - if (std::holds_alternative(control.u)) { + if (std::holds_alternative(control.u)) return true; - } } } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { for (const auto &waitSpec : stmt.v) { - if (std::holds_alternative(waitSpec.u)) { + if (std::holds_alternative(waitSpec.u)) return true; - } } } return false; } -bool hasAltReturns(const Pa::CallStmt &callStmt) { - const auto &args{std::get>(callStmt.v.t)}; +bool hasAltReturns(const Fortran::parser::CallStmt &callStmt) { + const auto &args{ + std::get>(callStmt.v.t)}; for (const auto &arg : args) { - const auto &actual{std::get(arg.t)}; - if (std::holds_alternative(actual.u)) { + const auto &actual{std::get(arg.t)}; + if (std::holds_alternative(actual.u)) return true; - } } return false; } /// Determine if `callStmt` has alternate returns and if so set `e` to be the /// origin of a switch-like control flow -void altRet(AST::Evaluation &e, const Pa::CallStmt *callStmt, - AST::Evaluation *cstr) { - if (hasAltReturns(*callStmt)) { - e.setCFG(AST::CFGAnnotation::Switch, cstr); - } +void altRet(Fortran::lower::AST::Evaluation &evaluation, + const Fortran::parser::CallStmt *callStmt, + Fortran::lower::AST::Evaluation *cstr) { + if (hasAltReturns(*callStmt)) + evaluation.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); } template -void ioLabel(AST::Evaluation &e, const A *s, AST::Evaluation *cstr) { - if (hasErrLabel(*s) || hasEorLabel(*s) || hasEndLabel(*s)) { - e.setCFG(AST::CFGAnnotation::IoSwitch, cstr); - } +void ioLabel(Fortran::lower::AST::Evaluation &evaluation, const A *statement, + Fortran::lower::AST::Evaluation *cstr) { + if (hasErrLabel(*statement) || hasEorLabel(*statement) || + hasEndLabel(*statement)) + evaluation.setCFG(Fortran::lower::AST::CFGAnnotation::IoSwitch, cstr); } -void annotateEvalListCFG(std::list &evals, - AST::Evaluation *cstr) { +void annotateEvalListCFG( + Fortran::lower::AST::EvaluationCollection &evaluationCollection, + Fortran::lower::AST::Evaluation *cstr) { bool nextIsTarget = false; - for (auto &e : evals) { - e.isTarget = nextIsTarget; + for (auto &eval : evaluationCollection) { + eval.isTarget = nextIsTarget; nextIsTarget = false; - if (e.isConstruct()) { - annotateEvalListCFG(*e.getConstructEvals(), &e); + if (eval.isConstruct()) { + annotateEvalListCFG(*eval.getConstructEvals(), &eval); // assume that the entry and exit are both possible branch targets nextIsTarget = true; } - if (e.isActionStmt() && e.lab.has_value()) { - e.isTarget = true; - } + if (eval.isActionStmt() && eval.lab.has_value()) + eval.isTarget = true; std::visit( - Co::visitors{ - [&](const Pa::BackspaceStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::CallStmt *s) { altRet(e, s, cstr); }, - [&](const Pa::CloseStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::CycleStmt *) { - e.setCFG(AST::CFGAnnotation::Goto, cstr); + Fortran::common::visitors{ + [&](const Fortran::parser::BackspaceStmt *statement) { + ioLabel(eval, statement, cstr); + }, + [&](const Fortran::parser::CallStmt *statement) { + altRet(eval, statement, cstr); + }, + [&](const Fortran::parser::CloseStmt *statement) { + ioLabel(eval, statement, cstr); + }, + [&](const Fortran::parser::CycleStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + }, + [&](const Fortran::parser::EndfileStmt *statement) { + ioLabel(eval, statement, cstr); + }, + [&](const Fortran::parser::ExitStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + }, + [&](const Fortran::parser::FailImageStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Terminate, cstr); + }, + [&](const Fortran::parser::FlushStmt *statement) { + ioLabel(eval, statement, cstr); + }, + [&](const Fortran::parser::GotoStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); }, - [&](const Pa::EndfileStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::ExitStmt *) { - e.setCFG(AST::CFGAnnotation::Goto, cstr); + [&](const Fortran::parser::IfStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Pa::FailImageStmt *) { - e.setCFG(AST::CFGAnnotation::Terminate, cstr); + [&](const Fortran::parser::InquireStmt *statement) { + ioLabel(eval, statement, cstr); }, - [&](const Pa::FlushStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::GotoStmt *) { - e.setCFG(AST::CFGAnnotation::Goto, cstr); + [&](const Fortran::parser::OpenStmt *statement) { + ioLabel(eval, statement, cstr); }, - [&](const Pa::IfStmt *) { - e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + [&](const Fortran::parser::ReadStmt *statement) { + ioLabel(eval, statement, cstr); }, - [&](const Pa::InquireStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::OpenStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::ReadStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::ReturnStmt *) { - e.setCFG(AST::CFGAnnotation::Return, cstr); + [&](const Fortran::parser::ReturnStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Return, cstr); }, - [&](const Pa::RewindStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::StopStmt *) { - e.setCFG(AST::CFGAnnotation::Terminate, cstr); + [&](const Fortran::parser::RewindStmt *statement) { + ioLabel(eval, statement, cstr); }, - [&](const Pa::WaitStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::WriteStmt *s) { ioLabel(e, s, cstr); }, - [&](const Pa::ArithmeticIfStmt *) { - e.setCFG(AST::CFGAnnotation::Switch, cstr); + [&](const Fortran::parser::StopStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Terminate, cstr); }, - [&](const Pa::AssignedGotoStmt *) { - e.setCFG(AST::CFGAnnotation::IndGoto, cstr); + [&](const Fortran::parser::WaitStmt *statement) { + ioLabel(eval, statement, cstr); }, - [&](const Pa::ComputedGotoStmt *) { - e.setCFG(AST::CFGAnnotation::Switch, cstr); + [&](const Fortran::parser::WriteStmt *statement) { + ioLabel(eval, statement, cstr); }, - [&](const Pa::WhereStmt *) { + [&](const Fortran::parser::ArithmeticIfStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + }, + [&](const Fortran::parser::AssignedGotoStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::IndGoto, cstr); + }, + [&](const Fortran::parser::ComputedGotoStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + }, + [&](const Fortran::parser::WhereStmt *) { // fir.loop + fir.where around the next stmt - e.isTarget = true; - e.setCFG(AST::CFGAnnotation::Iterative, cstr); + eval.isTarget = true; + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); }, - [&](const Pa::ForallStmt *) { + [&](const Fortran::parser::ForallStmt *) { // fir.loop around the next stmt - e.isTarget = true; - e.setCFG(AST::CFGAnnotation::Iterative, cstr); - }, - [&](AST::CGJump &) { e.setCFG(AST::CFGAnnotation::Goto, cstr); }, - [&](const Pa::EndAssociateStmt *) { e.isTarget = true; }, - [&](const Pa::EndBlockStmt *) { e.isTarget = true; }, - [&](const Pa::SelectCaseStmt *) { - e.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const Pa::CaseStmt *) { e.isTarget = true; }, - [&](const Pa::EndSelectStmt *) { e.isTarget = true; }, - [&](const Pa::EndChangeTeamStmt *) { e.isTarget = true; }, - [&](const Pa::EndCriticalStmt *) { e.isTarget = true; }, - [&](const Pa::NonLabelDoStmt *) { - e.isTarget = true; - e.setCFG(AST::CFGAnnotation::Iterative, cstr); - }, - [&](const Pa::EndDoStmt *) { - e.isTarget = true; - e.setCFG(AST::CFGAnnotation::Goto, cstr); - }, - [&](const Pa::IfThenStmt *) { - e.setCFG(AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const Pa::ElseIfStmt *) { - e.setCFG(AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const Pa::ElseStmt *) { e.isTarget = true; }, - [&](const Pa::EndIfStmt *) { e.isTarget = true; }, - [&](const Pa::SelectRankStmt *) { - e.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const Pa::SelectRankCaseStmt *) { e.isTarget = true; }, - [&](const Pa::SelectTypeStmt *) { - e.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const Pa::TypeGuardStmt *) { e.isTarget = true; }, - [&](const Pa::WhereConstruct *) { + eval.isTarget = true; + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); + }, + [&](Fortran::lower::AST::CGJump &) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + }, + [&](const Fortran::parser::EndAssociateStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::EndBlockStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::SelectCaseStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + }, + [&](const Fortran::parser::CaseStmt *) { eval.isTarget = true; }, + [&](const Fortran::parser::EndSelectStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::EndChangeTeamStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::EndCriticalStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::NonLabelDoStmt *) { + eval.isTarget = true; + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); + }, + [&](const Fortran::parser::EndDoStmt *) { + eval.isTarget = true; + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + }, + [&](const Fortran::parser::IfThenStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const Fortran::parser::ElseIfStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const Fortran::parser::ElseStmt *) { eval.isTarget = true; }, + [&](const Fortran::parser::EndIfStmt *) { eval.isTarget = true; }, + [&](const Fortran::parser::SelectRankStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + }, + [&](const Fortran::parser::SelectRankCaseStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::SelectTypeStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + }, + [&](const Fortran::parser::TypeGuardStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::WhereConstruct *) { // mark the WHERE as if it were a DO loop - e.isTarget = true; - e.setCFG(AST::CFGAnnotation::Iterative, cstr); + eval.isTarget = true; + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); + }, + [&](const Fortran::parser::WhereConstructStmt *) { + eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Pa::WhereConstructStmt *) { - e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + [&](const Fortran::parser::MaskedElsewhereStmt *) { + eval.isTarget = true; + eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Pa::MaskedElsewhereStmt *) { - e.isTarget = true; - e.setCFG(AST::CFGAnnotation::CondGoto, cstr); + [&](const Fortran::parser::ElsewhereStmt *) { + eval.isTarget = true; }, - [&](const Pa::ElsewhereStmt *) { e.isTarget = true; }, - [&](const Pa::EndWhereStmt *) { e.isTarget = true; }, - [&](const Pa::ForallConstructStmt *) { - e.isTarget = true; - e.setCFG(AST::CFGAnnotation::Iterative, cstr); + [&](const Fortran::parser::EndWhereStmt *) { + eval.isTarget = true; + }, + [&](const Fortran::parser::ForallConstructStmt *) { + eval.isTarget = true; + eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); + }, + [&](const Fortran::parser::EndForallStmt *) { + eval.isTarget = true; }, - [&](const Pa::EndForallStmt *) { e.isTarget = true; }, [](const auto *) { /* do nothing */ }, }, - e.u); + eval.u); } } /// Annotate the AST with CFG source decorations (see CFGAnnotation) and mark /// potential branch targets -inline void annotateFuncCFG(AST::FunctionLikeUnit &flu) { - annotateEvalListCFG(flu.evals, nullptr); +inline void +annotateFuncCFG(Fortran::lower::AST::FunctionLikeUnit &functionLikeUnit) { + annotateEvalListCFG(functionLikeUnit.evals, nullptr); } -L::StringRef evalName(AST::Evaluation &e) { +llvm::StringRef evalName(Fortran::lower::AST::Evaluation &eval) { return std::visit( - Co::visitors{[](const AST::CGJump) { return "CGJump"; }, - [](const auto *parseTreeNode) { - assert(parseTreeNode && "nullptr node in AST "); - return Pa::ParseTreeDumper::GetNodeName(*parseTreeNode); - }}, - e.u); + Fortran::common::visitors{ + [](const Fortran::lower::AST::CGJump) { return "CGJump"; }, + [](const auto *parseTreeNode) { + assert(parseTreeNode && "nullptr node in AST "); + return Fortran::parser::ParseTreeDumper::GetNodeName( + *parseTreeNode); + }}, + eval.u); } -void dumpEvalList(L::raw_ostream &o, std::list &evals, - int indent = 1) { +void dumpEvalList( + llvm::raw_ostream &outputStream, + Fortran::lower::AST::EvaluationCollection &evaluationCollection, + int indent = 1) { static const std::string white{" ++"}; std::string indentString{white.substr(0, indent * 2)}; - for (AST::Evaluation &e : evals) { - L::StringRef name{evalName(e)}; - if (e.isConstruct()) { - o << indentString << "<<" << name << ">>\n"; - dumpEvalList(o, *e.getConstructEvals(), indent + 1); - o << indentString << "<>\n"; + for (Fortran::lower::AST::Evaluation &eval : evaluationCollection) { + llvm::StringRef name{evalName(eval)}; + if (eval.isConstruct()) { + outputStream << indentString << "<<" << name << ">>\n"; + dumpEvalList(outputStream, *eval.getConstructEvals(), indent + 1); + outputStream << indentString << "<>\n"; } else { - o << indentString << name << ": " << e.pos.ToString() << '\n'; + outputStream << indentString << name << ": " << eval.pos.ToString() + << '\n'; } } } -void dumpFunctionLikeUnit(L::raw_ostream &o, AST::FunctionLikeUnit &flu) { - L::StringRef unitKind{}; +void dumpFunctionLikeUnit( + llvm::raw_ostream &outputStream, + Fortran::lower::AST::FunctionLikeUnit &functionLikeUnit) { + llvm::StringRef unitKind{}; std::string name{}; std::string header{}; - std::visit(Co::visitors{ - [&](const Pa::Statement *s) { - unitKind = "Program"; - name = s->statement.v.ToString(); - }, - [&](const Pa::Statement *s) { - unitKind = "Function"; - name = std::get(s->statement.t).ToString(); - header = s->source.ToString(); - }, - [&](const Pa::Statement *s) { - unitKind = "Subroutine"; - name = std::get(s->statement.t).ToString(); - header = s->source.ToString(); - }, - [&](const Pa::Statement *s) { - unitKind = "MpSubprogram"; - name = s->statement.v.ToString(); - header = s->source.ToString(); - }, - [&](auto *) { - if (std::get_if *>( - &flu.funStmts.back())) { - unitKind = "Program"; - name = ""; - } else { - unitKind = ">>>>> Error - no program unit <<<<<"; - } - }, - }, - flu.funStmts.front()); - o << unitKind << ' ' << name; - if (header.size()) { - o << ": " << header; - } - o << '\n'; - dumpEvalList(o, flu.evals); - o << "End" << unitKind << ' ' << name << "\n\n"; + std::visit( + Fortran::common::visitors{ + [&](const Fortran::parser::Statement + *statement) { + unitKind = "Program"; + name = statement->statement.v.ToString(); + }, + [&](const Fortran::parser::Statement + *statement) { + unitKind = "Function"; + name = std::get(statement->statement.t) + .ToString(); + header = statement->source.ToString(); + }, + [&](const Fortran::parser::Statement + *statement) { + unitKind = "Subroutine"; + name = std::get(statement->statement.t) + .ToString(); + header = statement->source.ToString(); + }, + [&](const Fortran::parser::Statement< + Fortran::parser::MpSubprogramStmt> *statement) { + unitKind = "MpSubprogram"; + name = statement->statement.v.ToString(); + header = statement->source.ToString(); + }, + [&](auto *) { + if (std::get_if *>( + &functionLikeUnit.funStmts.back())) { + unitKind = "Program"; + name = ""; + } else { + unitKind = ">>>>> Error - no program unit <<<<<"; + } + }, + }, + functionLikeUnit.funStmts.front()); + outputStream << unitKind << ' ' << name; + if (header.size()) + outputStream << ": " << header; + outputStream << '\n'; + dumpEvalList(outputStream, functionLikeUnit.evals); + outputStream << "End" << unitKind << ' ' << name << "\n\n"; } } // namespace -Br::AST::FunctionLikeUnit::FunctionLikeUnit(const Pa::MainProgram &f, - const AST::ParentType &parent) - : ProgramUnit{&f, parent} { - auto &ps{std::get>>(f.t)}; +Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( + const Fortran::parser::MainProgram &func, + const Fortran::lower::AST::ParentType &parent) + : ProgramUnit{&func, parent} { + auto &ps{std::get< + std::optional>>( + func.t)}; if (ps.has_value()) { - const Pa::Statement &s{ps.value()}; - funStmts.push_back(&s); + const Fortran::parser::Statement &statement{ + ps.value()}; + funStmts.push_back(&statement); } - funStmts.push_back(&std::get>(f.t)); + funStmts.push_back( + &std::get>( + func.t)); } -Br::AST::FunctionLikeUnit::FunctionLikeUnit(const Pa::FunctionSubprogram &f, - const AST::ParentType &parent) - : ProgramUnit{&f, parent} { - funStmts.push_back(&std::get>(f.t)); - funStmts.push_back(&std::get>(f.t)); +Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( + const Fortran::parser::FunctionSubprogram &func, + const Fortran::lower::AST::ParentType &parent) + : ProgramUnit{&func, parent} { + funStmts.push_back( + &std::get>( + func.t)); + funStmts.push_back( + &std::get>( + func.t)); } -Br::AST::FunctionLikeUnit::FunctionLikeUnit(const Pa::SubroutineSubprogram &f, - const AST::ParentType &parent) - : ProgramUnit{&f, parent} { - funStmts.push_back(&std::get>(f.t)); - funStmts.push_back(&std::get>(f.t)); +Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( + const Fortran::parser::SubroutineSubprogram &func, + const Fortran::lower::AST::ParentType &parent) + : ProgramUnit{&func, parent} { + funStmts.push_back( + &std::get>( + func.t)); + funStmts.push_back( + &std::get>( + func.t)); } -Br::AST::FunctionLikeUnit::FunctionLikeUnit( - const Pa::SeparateModuleSubprogram &f, const AST::ParentType &parent) - : ProgramUnit{&f, parent} { - funStmts.push_back(&std::get>(f.t)); - funStmts.push_back(&std::get>(f.t)); +Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( + const Fortran::parser::SeparateModuleSubprogram &func, + const Fortran::lower::AST::ParentType &parent) + : ProgramUnit{&func, parent} { + funStmts.push_back( + &std::get>( + func.t)); + funStmts.push_back( + &std::get< + Fortran::parser::Statement>( + func.t)); } -Br::AST::ModuleLikeUnit::ModuleLikeUnit(const Pa::Module &m, - const AST::ParentType &parent) +Fortran::lower::AST::ModuleLikeUnit::ModuleLikeUnit( + const Fortran::parser::Module &m, + const Fortran::lower::AST::ParentType &parent) : ProgramUnit{&m, parent} { - modStmts.push_back(&std::get>(m.t)); - modStmts.push_back(&std::get>(m.t)); + modStmts.push_back( + &std::get>(m.t)); + modStmts.push_back( + &std::get>( + m.t)); } -Br::AST::ModuleLikeUnit::ModuleLikeUnit(const Pa::Submodule &m, - const AST::ParentType &parent) +Fortran::lower::AST::ModuleLikeUnit::ModuleLikeUnit( + const Fortran::parser::Submodule &m, + const Fortran::lower::AST::ParentType &parent) : ProgramUnit{&m, parent} { - modStmts.push_back(&std::get>(m.t)); - modStmts.push_back(&std::get>(m.t)); + modStmts.push_back( + &std::get>( + m.t)); + modStmts.push_back( + &std::get>( + m.t)); } -Br::AST::BlockDataUnit::BlockDataUnit(const Pa::BlockData &bd, - const AST::ParentType &parent) +Fortran::lower::AST::BlockDataUnit::BlockDataUnit( + const Fortran::parser::BlockData &bd, + const Fortran::lower::AST::ParentType &parent) : ProgramUnit{&bd, parent} {} -AST::Program *Br::createAST(const Pa::Program &root) { +Fortran::lower::AST::Program * +Fortran::lower::createAST(const Fortran::parser::Program &root) { ASTBuilder walker; Walk(root, walker); return walker.result(); } -void Br::annotateControl(AST::Program &ast) { +void Fortran::lower::annotateControl(Fortran::lower::AST::Program &ast) { for (auto &unit : ast.getUnits()) { - std::visit(Co::visitors{ - [](AST::BlockDataUnit &) {}, - [](AST::FunctionLikeUnit &f) { - annotateFuncCFG(f); - for (auto &s : f.funcs) { - annotateFuncCFG(s); + std::visit(Fortran::common::visitors{ + [](Fortran::lower::AST::BlockDataUnit &) {}, + [](Fortran::lower::AST::FunctionLikeUnit &func) { + annotateFuncCFG(func); + for (auto &statement : func.funcs) { + annotateFuncCFG(statement); } }, - [](AST::ModuleLikeUnit &u) { - for (auto &f : u.funcs) { - annotateFuncCFG(f); + [](Fortran::lower::AST::ModuleLikeUnit &unit) { + for (auto &func : unit.funcs) { + annotateFuncCFG(func); } }, }, @@ -761,23 +936,25 @@ void Br::annotateControl(AST::Program &ast) { } /// Dump an AST. -void Br::dumpAST(L::raw_ostream &o, AST::Program &ast) { +void Fortran::lower::dumpAST(llvm::raw_ostream &outputStream, + Fortran::lower::AST::Program &ast) { for (auto &unit : ast.getUnits()) { - std::visit( - Co::visitors{ - [&](AST::BlockDataUnit &) { o << "BlockData\nEndBlockData\n\n"; }, - [&](AST::FunctionLikeUnit &f) { - dumpFunctionLikeUnit(o, f); - for (auto &f : f.funcs) { - dumpFunctionLikeUnit(o, f); - } - }, - [&](AST::ModuleLikeUnit &u) { - for (auto &f : u.funcs) { - dumpFunctionLikeUnit(o, f); - } - }, - }, - unit); + std::visit(Fortran::common::visitors{ + [&](Fortran::lower::AST::BlockDataUnit &) { + outputStream << "BlockData\nEndBlockData\n\n"; + }, + [&](Fortran::lower::AST::FunctionLikeUnit &func) { + dumpFunctionLikeUnit(outputStream, func); + for (auto &func : func.funcs) { + dumpFunctionLikeUnit(outputStream, func); + } + }, + [&](Fortran::lower::AST::ModuleLikeUnit &unit) { + for (auto &func : unit.funcs) { + dumpFunctionLikeUnit(outputStream, func); + } + }, + }, + unit); } } From 3d333b6079829f9cd4cbd4b0e4f9f6f02d6844ec Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 30 Jan 2020 04:15:27 -0800 Subject: [PATCH 06/24] [review 959] Use std::any_of and isAction renaming --- include/flang/lower/ASTBuilder.h | 19 ++++++++++--------- lib/lower/ASTBuilder.cpp | 25 +++++++++++-------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 4cc496a8cc14..725d4c74087e 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -170,9 +170,9 @@ struct Evaluation { static_assert(AST::isConstruct(), "must be a construct"); } - /// is `A` executable (an action statement or compiler generated)? + /// is `A` an action statement ? template - constexpr static bool isAction(const A &a) { + constexpr static bool isActionStmt(const A &a) { return !AST::isConstruct() && !isOther(a); } @@ -191,20 +191,21 @@ struct Evaluation { std::is_same_v; } - constexpr bool isActionStmt() const { + constexpr bool isActionOrGenerated() const { return std::visit(common::visitors{ - [](auto *p) { return isAction(*p); }, + [](auto *p) { return isActionStmt(*p); }, [](auto &r) { return isGenerated(r); }, }, u); } constexpr bool isStmt() const { - return std::visit(common::visitors{ - [](auto *p) { return isAction(*p) || isOther(*p); }, - [](auto &r) { return isGenerated(r); }, - }, - u); + return std::visit( + common::visitors{ + [](auto *p) { return isActionStmt(*p) || isOther(*p); }, + [](auto &r) { return isGenerated(r); }, + }, + u); } constexpr bool isConstruct() const { return !isStmt(); } diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index 5b3f728b77ee..ae0f6b1e36c9 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -9,6 +9,7 @@ #include "flang/lower/ASTBuilder.h" #include "flang/parser/dump-parse-tree.h" #include "flang/parser/parse-tree-visitor.h" +#include #include #include @@ -470,12 +471,13 @@ class ASTBuilder { template constexpr bool hasErrLabel(const A &stmt) { + auto isError{[](const auto &v) { + return std::holds_alternative(v.u); + }}; if constexpr (std::is_same_v || std::is_same_v) { - for (const auto &control : stmt.controls) { - if (std::holds_alternative(control.u)) - return true; - } + return std::any_of(std::begin(stmt.controls), std::end(stmt.controls), + isError); } if constexpr (std::is_same_v || std::is_same_v || @@ -484,17 +486,12 @@ constexpr bool hasErrLabel(const A &stmt) { std::is_same_v || std::is_same_v || std::is_same_v) { - for (const auto &spec : stmt.v) { - if (std::holds_alternative(spec.u)) - return true; - } + return std::any_of(std::begin(stmt.v), std::end(stmt.v), isError); } if constexpr (std::is_same_v) { - for (const auto &spec : - std::get>(stmt.u)) { - if (std::holds_alternative(spec.u)) - return true; - } + const auto &specifiers{ + std::get>(stmt.u)}; + return std::any_of(std::begin(specifiers), std::end(specifiers), isError); } return false; } @@ -575,7 +572,7 @@ void annotateEvalListCFG( // assume that the entry and exit are both possible branch targets nextIsTarget = true; } - if (eval.isActionStmt() && eval.lab.has_value()) + if (eval.isActionOrGenerated() && eval.lab.has_value()) eval.isTarget = true; std::visit( Fortran::common::visitors{ From 3ccfba1f01af418eda2b05cc6b6409e939d78fe3 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 30 Jan 2020 05:08:35 -0800 Subject: [PATCH 07/24] [review 959] Make ASTBuilder::pgm a std::unique_ptr --- include/flang/lower/ASTBuilder.h | 3 ++- lib/lower/ASTBuilder.cpp | 13 ++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 725d4c74087e..48b06dfb4068 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -12,6 +12,7 @@ #include "flang/parser/parse-tree.h" #include "flang/semantics/scope.h" #include "llvm/Support/raw_ostream.h" +#include namespace Fortran::lower { namespace AST { @@ -351,7 +352,7 @@ struct Program { } // namespace AST /// Create an AST from the parse tree -AST::Program *createAST(const Fortran::parser::Program &root); +std::unique_ptr createAST(const Fortran::parser::Program &root); /// Decorate the AST with control flow annotations /// diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index ae0f6b1e36c9..165724b68d07 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -30,13 +30,12 @@ namespace { /// the bridge to one such instantiation. class ASTBuilder { public: - ASTBuilder() { - pgm = new Fortran::lower::AST::Program; - parents.push_back(pgm); - } + ASTBuilder() : pgm{new Fortran::lower::AST::Program}, parents{pgm.get()} {} /// Get the result - Fortran::lower::AST::Program *result() { return pgm; } + std::unique_ptr result() { + return std::move(pgm); + } template constexpr bool Pre(const A &) { @@ -463,7 +462,7 @@ class ASTBuilder { evallist.pop_back(); } - Fortran::lower::AST::Program *pgm; + std::unique_ptr pgm; std::list *funclist{nullptr}; std::vector evallist; std::vector parents; @@ -905,7 +904,7 @@ Fortran::lower::AST::BlockDataUnit::BlockDataUnit( const Fortran::lower::AST::ParentType &parent) : ProgramUnit{&bd, parent} {} -Fortran::lower::AST::Program * +std::unique_ptr Fortran::lower::createAST(const Fortran::parser::Program &root) { ASTBuilder walker; Walk(root, walker); From 132cd6d94de3ce09143166b1c95391886c19b619 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 30 Jan 2020 08:17:26 -0800 Subject: [PATCH 08/24] [review 959] Make Evaluation::subs a std::unique_ptr --- include/flang/lower/ASTBuilder.h | 19 ++++++++++++++++--- lib/lower/ASTBuilder.cpp | 17 ++++++++--------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 48b06dfb4068..6fbbc237c47c 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -152,7 +152,8 @@ struct Evaluation { const Fortran::parser::EndForallStmt *>; Evaluation() = delete; - Evaluation(const Evaluation &) = default; + Evaluation(const Evaluation &) = delete; + Evaluation(Evaluation &&) = default; /// General ctor template @@ -227,7 +228,7 @@ struct Evaluation { void setBranches() { containsBranches = true; } constexpr EvaluationCollection *getConstructEvals() { - return isStmt() ? nullptr : subs; + return isStmt() ? nullptr : subs.get(); } /// Set that the construct `cstr` (if not a nullptr) has branches. @@ -240,7 +241,7 @@ struct Evaluation { ParentType parent; Fortran::parser::CharBlock pos; std::optional lab; - EvaluationCollection *subs; // construct sub-statements + std::unique_ptr subs; // construct sub-statements CFGAnnotation cfg{CFGAnnotation::None}; bool isTarget{false}; // this evaluation is a control target bool containsBranches{false}; // construct contains branches @@ -251,6 +252,8 @@ struct Evaluation { struct ProgramUnit { template ProgramUnit(A *ptr, const ParentType &parent) : p{ptr}, parent{parent} {} + ProgramUnit(ProgramUnit &&) = default; + ProgramUnit(const ProgramUnit &) = delete; std::variant modStmts; @@ -337,12 +344,18 @@ struct ModuleLikeUnit : public ProgramUnit { struct BlockDataUnit : public ProgramUnit { BlockDataUnit(const Fortran::parser::BlockData &bd, const ParentType &parent); + BlockDataUnit(BlockDataUnit &&) = default; + BlockDataUnit(const BlockDataUnit &) = delete; }; /// A Program is the top-level AST struct Program { using Units = std::variant; + Program() = default; + Program(Program &&) = default; + Program(const Program &) = delete; + std::list &getUnits() { return units; } private: diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index 165724b68d07..6fa3a40dd154 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -73,8 +73,7 @@ class ASTBuilder { // Block data void Post(const Fortran::parser::BlockData &node) { - Fortran::lower::AST::BlockDataUnit unit{node, parents.back()}; - addUnit(unit); + addUnit(Fortran::lower::AST::BlockDataUnit{node, parents.back()}); } // @@ -398,8 +397,8 @@ class ASTBuilder { bool enterConstruct(const A &construct) { auto &con = addEval(Fortran::lower::AST::Evaluation{construct, parents.back()}); - con.subs = new Fortran::lower::AST::EvaluationCollection; - pushEval(con.subs); + con.subs.reset(new Fortran::lower::AST::EvaluationCollection); + pushEval(con.subs.get()); parents.emplace_back(&con); return true; } @@ -426,18 +425,18 @@ class ASTBuilder { } template - A &addUnit(const A &unit) { - pgm->getUnits().emplace_back(unit); + A &addUnit(A &&unit) { + pgm->getUnits().emplace_back(std::move(unit)); return std::get(pgm->getUnits().back()); } template - A &addFunc(const A &func) { + A &addFunc(A &&func) { if (funclist) { - funclist->emplace_back(func); + funclist->emplace_back(std::move(func)); return funclist->back(); } - return addUnit(func); + return addUnit(std::move(func)); } /// move the Evaluation to the end of the current list From 4a73dec857715a18da053599182b041c61414c51 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 30 Jan 2020 08:33:45 -0800 Subject: [PATCH 09/24] [review 959] Namespace changes Remove Fortran:: and Fortran::lower when not needed. --- include/flang/lower/ASTBuilder.h | 236 +++++------ lib/lower/ASTBuilder.cpp | 705 +++++++++++++------------------ 2 files changed, 398 insertions(+), 543 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 6fbbc237c47c..3f1dc1ad1bea 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -55,20 +55,20 @@ struct CGJump { /// is `A` a construct (or directive)? template constexpr static bool isConstruct() { - return std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; + return std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; } /// Function-like units can contains lists of evaluations. These can be @@ -77,79 +77,55 @@ constexpr static bool isConstruct() { struct Evaluation { using EvalVariant = std::variant< // action statements - const Fortran::parser::AllocateStmt *, - const Fortran::parser::AssignmentStmt *, - const Fortran::parser::BackspaceStmt *, const Fortran::parser::CallStmt *, - const Fortran::parser::CloseStmt *, const Fortran::parser::ContinueStmt *, - const Fortran::parser::CycleStmt *, - const Fortran::parser::DeallocateStmt *, - const Fortran::parser::EndfileStmt *, - const Fortran::parser::EventPostStmt *, - const Fortran::parser::EventWaitStmt *, const Fortran::parser::ExitStmt *, - const Fortran::parser::FailImageStmt *, - const Fortran::parser::FlushStmt *, const Fortran::parser::FormTeamStmt *, - const Fortran::parser::GotoStmt *, const Fortran::parser::IfStmt *, - const Fortran::parser::InquireStmt *, const Fortran::parser::LockStmt *, - const Fortran::parser::NullifyStmt *, const Fortran::parser::OpenStmt *, - const Fortran::parser::PointerAssignmentStmt *, - const Fortran::parser::PrintStmt *, const Fortran::parser::ReadStmt *, - const Fortran::parser::ReturnStmt *, const Fortran::parser::RewindStmt *, - const Fortran::parser::StopStmt *, const Fortran::parser::SyncAllStmt *, - const Fortran::parser::SyncImagesStmt *, - const Fortran::parser::SyncMemoryStmt *, - const Fortran::parser::SyncTeamStmt *, - const Fortran::parser::UnlockStmt *, const Fortran::parser::WaitStmt *, - const Fortran::parser::WhereStmt *, const Fortran::parser::WriteStmt *, - const Fortran::parser::ComputedGotoStmt *, - const Fortran::parser::ForallStmt *, - const Fortran::parser::ArithmeticIfStmt *, - const Fortran::parser::AssignStmt *, - const Fortran::parser::AssignedGotoStmt *, - const Fortran::parser::PauseStmt *, + const parser::AllocateStmt *, const parser::AssignmentStmt *, + const parser::BackspaceStmt *, const parser::CallStmt *, + const parser::CloseStmt *, const parser::ContinueStmt *, + const parser::CycleStmt *, const parser::DeallocateStmt *, + const parser::EndfileStmt *, const parser::EventPostStmt *, + const parser::EventWaitStmt *, const parser::ExitStmt *, + const parser::FailImageStmt *, const parser::FlushStmt *, + const parser::FormTeamStmt *, const parser::GotoStmt *, + const parser::IfStmt *, const parser::InquireStmt *, + const parser::LockStmt *, const parser::NullifyStmt *, + const parser::OpenStmt *, const parser::PointerAssignmentStmt *, + const parser::PrintStmt *, const parser::ReadStmt *, + const parser::ReturnStmt *, const parser::RewindStmt *, + const parser::StopStmt *, const parser::SyncAllStmt *, + const parser::SyncImagesStmt *, const parser::SyncMemoryStmt *, + const parser::SyncTeamStmt *, const parser::UnlockStmt *, + const parser::WaitStmt *, const parser::WhereStmt *, + const parser::WriteStmt *, const parser::ComputedGotoStmt *, + const parser::ForallStmt *, const parser::ArithmeticIfStmt *, + const parser::AssignStmt *, const parser::AssignedGotoStmt *, + const parser::PauseStmt *, // compiler generated ops CGJump, // other statements - const Fortran::parser::FormatStmt *, const Fortran::parser::EntryStmt *, - const Fortran::parser::DataStmt *, const Fortran::parser::NamelistStmt *, + const parser::FormatStmt *, const parser::EntryStmt *, + const parser::DataStmt *, const parser::NamelistStmt *, // constructs - const Fortran::parser::AssociateConstruct *, - const Fortran::parser::BlockConstruct *, - const Fortran::parser::CaseConstruct *, - const Fortran::parser::ChangeTeamConstruct *, - const Fortran::parser::CriticalConstruct *, - const Fortran::parser::DoConstruct *, - const Fortran::parser::IfConstruct *, - const Fortran::parser::SelectRankConstruct *, - const Fortran::parser::SelectTypeConstruct *, - const Fortran::parser::WhereConstruct *, - const Fortran::parser::ForallConstruct *, - const Fortran::parser::CompilerDirective *, - const Fortran::parser::OpenMPConstruct *, - const Fortran::parser::OmpEndLoopDirective *, + const parser::AssociateConstruct *, const parser::BlockConstruct *, + const parser::CaseConstruct *, const parser::ChangeTeamConstruct *, + const parser::CriticalConstruct *, const parser::DoConstruct *, + const parser::IfConstruct *, const parser::SelectRankConstruct *, + const parser::SelectTypeConstruct *, const parser::WhereConstruct *, + const parser::ForallConstruct *, const parser::CompilerDirective *, + const parser::OpenMPConstruct *, const parser::OmpEndLoopDirective *, // construct statements - const Fortran::parser::AssociateStmt *, - const Fortran::parser::EndAssociateStmt *, - const Fortran::parser::BlockStmt *, const Fortran::parser::EndBlockStmt *, - const Fortran::parser::SelectCaseStmt *, - const Fortran::parser::CaseStmt *, const Fortran::parser::EndSelectStmt *, - const Fortran::parser::ChangeTeamStmt *, - const Fortran::parser::EndChangeTeamStmt *, - const Fortran::parser::CriticalStmt *, - const Fortran::parser::EndCriticalStmt *, - const Fortran::parser::NonLabelDoStmt *, - const Fortran::parser::EndDoStmt *, const Fortran::parser::IfThenStmt *, - const Fortran::parser::ElseIfStmt *, const Fortran::parser::ElseStmt *, - const Fortran::parser::EndIfStmt *, - const Fortran::parser::SelectRankStmt *, - const Fortran::parser::SelectRankCaseStmt *, - const Fortran::parser::SelectTypeStmt *, - const Fortran::parser::TypeGuardStmt *, - const Fortran::parser::WhereConstructStmt *, - const Fortran::parser::MaskedElsewhereStmt *, - const Fortran::parser::ElsewhereStmt *, - const Fortran::parser::EndWhereStmt *, - const Fortran::parser::ForallConstructStmt *, - const Fortran::parser::EndForallStmt *>; + const parser::AssociateStmt *, const parser::EndAssociateStmt *, + const parser::BlockStmt *, const parser::EndBlockStmt *, + const parser::SelectCaseStmt *, const parser::CaseStmt *, + const parser::EndSelectStmt *, const parser::ChangeTeamStmt *, + const parser::EndChangeTeamStmt *, const parser::CriticalStmt *, + const parser::EndCriticalStmt *, const parser::NonLabelDoStmt *, + const parser::EndDoStmt *, const parser::IfThenStmt *, + const parser::ElseIfStmt *, const parser::ElseStmt *, + const parser::EndIfStmt *, const parser::SelectRankStmt *, + const parser::SelectRankCaseStmt *, const parser::SelectTypeStmt *, + const parser::TypeGuardStmt *, const parser::WhereConstructStmt *, + const parser::MaskedElsewhereStmt *, const parser::ElsewhereStmt *, + const parser::EndWhereStmt *, const parser::ForallConstructStmt *, + const parser::EndForallStmt *>; Evaluation() = delete; Evaluation(const Evaluation &) = delete; @@ -157,9 +133,8 @@ struct Evaluation { /// General ctor template - Evaluation(const A &a, const ParentType &p, - const Fortran::parser::CharBlock &pos, - const std::optional &lab) + Evaluation(const A &a, const ParentType &p, const parser::CharBlock &pos, + const std::optional &lab) : u{&a}, parent{p}, pos{pos}, lab{lab} {} /// Compiler-generated jump @@ -187,10 +162,10 @@ struct Evaluation { /// is `A` not an executable statement? template constexpr static bool isOther(const A &) { - return std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; + return std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; } constexpr bool isActionOrGenerated() const { @@ -239,8 +214,8 @@ struct Evaluation { EvalVariant u; ParentType parent; - Fortran::parser::CharBlock pos; - std::optional lab; + parser::CharBlock pos; + std::optional lab; std::unique_ptr subs; // construct sub-statements CFGAnnotation cfg{CFGAnnotation::None}; bool isTarget{false}; // this evaluation is a control target @@ -255,13 +230,11 @@ struct ProgramUnit { ProgramUnit(ProgramUnit &&) = default; ProgramUnit(const ProgramUnit &) = delete; - std::variant + std::variant p; ParentType parent; }; @@ -270,40 +243,38 @@ struct ProgramUnit { /// statements. struct FunctionLikeUnit : public ProgramUnit { // wrapper statements for function-like syntactic structures - using FunctionStatement = std::variant< - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *>; - - FunctionLikeUnit(const Fortran::parser::MainProgram &f, + using FunctionStatement = + std::variant *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *>; + + FunctionLikeUnit(const parser::MainProgram &f, const ParentType &parent); + FunctionLikeUnit(const parser::FunctionSubprogram &f, const ParentType &parent); - FunctionLikeUnit(const Fortran::parser::FunctionSubprogram &f, + FunctionLikeUnit(const parser::SubroutineSubprogram &f, const ParentType &parent); - FunctionLikeUnit(const Fortran::parser::SubroutineSubprogram &f, - const ParentType &parent); - FunctionLikeUnit(const Fortran::parser::SeparateModuleSubprogram &f, + FunctionLikeUnit(const parser::SeparateModuleSubprogram &f, const ParentType &parent); FunctionLikeUnit(FunctionLikeUnit &&) = default; FunctionLikeUnit(const FunctionLikeUnit &) = delete; bool isMainProgram() { return std::holds_alternative< - const Fortran::parser::Statement *>( - funStmts.back()); + const parser::Statement *>(funStmts.back()); } - const Fortran::parser::FunctionStmt *getFunction() { - return getA(); + const parser::FunctionStmt *getFunction() { + return getA(); } - const Fortran::parser::SubroutineStmt *getSubroutine() { - return getA(); + const parser::SubroutineStmt *getSubroutine() { + return getA(); } - const Fortran::parser::MpSubprogramStmt *getMPSubp() { - return getA(); + const parser::MpSubprogramStmt *getMPSubp() { + return getA(); } const semantics::Scope *scope{nullptr}; // scope from front-end @@ -314,8 +285,7 @@ struct FunctionLikeUnit : public ProgramUnit { private: template const A *getA() { - if (auto p = std::get_if *>( - &funStmts.front())) + if (auto p = std::get_if *>(&funStmts.front())) return &(*p)->statement; return nullptr; } @@ -325,14 +295,14 @@ struct FunctionLikeUnit : public ProgramUnit { /// function-like units. struct ModuleLikeUnit : public ProgramUnit { // wrapper statements for module-like syntactic structures - using ModuleStatement = std::variant< - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *, - const Fortran::parser::Statement *>; - - ModuleLikeUnit(const Fortran::parser::Module &m, const ParentType &parent); - ModuleLikeUnit(const Fortran::parser::Submodule &m, const ParentType &parent); + using ModuleStatement = + std::variant *, + const parser::Statement *, + const parser::Statement *, + const parser::Statement *>; + + ModuleLikeUnit(const parser::Module &m, const ParentType &parent); + ModuleLikeUnit(const parser::Submodule &m, const ParentType &parent); ~ModuleLikeUnit() = default; ModuleLikeUnit(ModuleLikeUnit &&) = default; ModuleLikeUnit(const ModuleLikeUnit &) = delete; @@ -343,7 +313,7 @@ struct ModuleLikeUnit : public ProgramUnit { }; struct BlockDataUnit : public ProgramUnit { - BlockDataUnit(const Fortran::parser::BlockData &bd, const ParentType &parent); + BlockDataUnit(const parser::BlockData &bd, const ParentType &parent); BlockDataUnit(BlockDataUnit &&) = default; BlockDataUnit(const BlockDataUnit &) = delete; }; @@ -365,7 +335,7 @@ struct Program { } // namespace AST /// Create an AST from the parse tree -std::unique_ptr createAST(const Fortran::parser::Program &root); +std::unique_ptr createAST(const parser::Program &root); /// Decorate the AST with control flow annotations /// diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index 6fa3a40dd154..fff32f7493d9 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -23,6 +23,7 @@ /// are either statements or constructs, where a construct contains a list of /// evaluations. The resulting AST structure can then be used to create FIR. +namespace Fortran::lower { namespace { /// The instantiation of a parse tree visitor (Pre and Post) is extremely @@ -30,12 +31,10 @@ namespace { /// the bridge to one such instantiation. class ASTBuilder { public: - ASTBuilder() : pgm{new Fortran::lower::AST::Program}, parents{pgm.get()} {} + ASTBuilder() : pgm{new AST::Program}, parents{pgm.get()} {} /// Get the result - std::unique_ptr result() { - return std::move(pgm); - } + std::unique_ptr result() { return std::move(pgm); } template constexpr bool Pre(const A &) { @@ -46,46 +45,40 @@ class ASTBuilder { // Module like - bool Pre(const Fortran::parser::Module &node) { return enterModule(node); } - bool Pre(const Fortran::parser::Submodule &node) { return enterModule(node); } + bool Pre(const parser::Module &node) { return enterModule(node); } + bool Pre(const parser::Submodule &node) { return enterModule(node); } - void Post(const Fortran::parser::Module &) { exitModule(); } - void Post(const Fortran::parser::Submodule &) { exitModule(); } + void Post(const parser::Module &) { exitModule(); } + void Post(const parser::Submodule &) { exitModule(); } // Function like - bool Pre(const Fortran::parser::MainProgram &node) { return enterFunc(node); } - bool Pre(const Fortran::parser::FunctionSubprogram &node) { - return enterFunc(node); - } - bool Pre(const Fortran::parser::SubroutineSubprogram &node) { - return enterFunc(node); - } - bool Pre(const Fortran::parser::SeparateModuleSubprogram &node) { + bool Pre(const parser::MainProgram &node) { return enterFunc(node); } + bool Pre(const parser::FunctionSubprogram &node) { return enterFunc(node); } + bool Pre(const parser::SubroutineSubprogram &node) { return enterFunc(node); } + bool Pre(const parser::SeparateModuleSubprogram &node) { return enterFunc(node); } - void Post(const Fortran::parser::MainProgram &) { exitFunc(); } - void Post(const Fortran::parser::FunctionSubprogram &) { exitFunc(); } - void Post(const Fortran::parser::SubroutineSubprogram &) { exitFunc(); } - void Post(const Fortran::parser::SeparateModuleSubprogram &) { exitFunc(); } + void Post(const parser::MainProgram &) { exitFunc(); } + void Post(const parser::FunctionSubprogram &) { exitFunc(); } + void Post(const parser::SubroutineSubprogram &) { exitFunc(); } + void Post(const parser::SeparateModuleSubprogram &) { exitFunc(); } // Block data - void Post(const Fortran::parser::BlockData &node) { - addUnit(Fortran::lower::AST::BlockDataUnit{node, parents.back()}); + void Post(const parser::BlockData &node) { + addUnit(AST::BlockDataUnit{node, parents.back()}); } // // Action statements // - void Post(const Fortran::parser::Statement &s) { + void Post(const parser::Statement &s) { addEval(makeEvalAction(s)); } - void - Post(const Fortran::parser::UnlabeledStatement - &s) { + void Post(const parser::UnlabeledStatement &s) { addEval(makeEvalAction(s)); } @@ -93,23 +86,20 @@ class ASTBuilder { // Non-executable statements // - void - Post(const Fortran::parser::Statement< - Fortran::common::Indirection> &statement) { + void Post(const parser::Statement> + &statement) { addEval(makeEvalIndirect(statement)); } - void - Post(const Fortran::parser::Statement< - Fortran::common::Indirection> &statement) { + void Post(const parser::Statement> + &statement) { addEval(makeEvalIndirect(statement)); } - void - Post(const Fortran::parser::Statement< - Fortran::common::Indirection> &statement) { + void Post(const parser::Statement> + &statement) { addEval(makeEvalIndirect(statement)); } - void Post(const Fortran::parser::Statement> &statement) { + void Post(const parser::Statement> + &statement) { addEval(makeEvalIndirect(statement)); } @@ -117,135 +107,101 @@ class ASTBuilder { // Construct statements // - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post( - const Fortran::parser::Statement &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void - Post(const Fortran::parser::Statement &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post( - const Fortran::parser::Statement &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void - Post(const Fortran::parser::Statement &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post( - const Fortran::parser::Statement &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void - Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void - Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void - Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void - Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } - void Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(makeEvalDirect(statement)); } // Get rid of production wrapper - void Post(const Fortran::parser::UnlabeledStatement< - Fortran::parser::ForallAssignmentStmt> &statement) { + void Post(const parser::UnlabeledStatement + &statement) { addEval(std::visit( [&](const auto &x) { - return Fortran::lower::AST::Evaluation{ - x, parents.back(), statement.source, {}}; + return AST::Evaluation{x, parents.back(), statement.source, {}}; }, statement.statement.u)); } - void - Post(const Fortran::parser::Statement - &statement) { + void Post(const parser::Statement &statement) { addEval(std::visit( [&](const auto &x) { - return Fortran::lower::AST::Evaluation{ - x, parents.back(), statement.source, statement.label}; + return AST::Evaluation{x, parents.back(), statement.source, + statement.label}; }, statement.statement.u)); } @@ -254,103 +210,99 @@ class ASTBuilder { // Constructs (enter and exit) // - bool Pre(const Fortran::parser::AssociateConstruct &construct) { + bool Pre(const parser::AssociateConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::BlockConstruct &construct) { + bool Pre(const parser::BlockConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::CaseConstruct &construct) { + bool Pre(const parser::CaseConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::ChangeTeamConstruct &construct) { + bool Pre(const parser::ChangeTeamConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::CriticalConstruct &construct) { + bool Pre(const parser::CriticalConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::DoConstruct &construct) { + bool Pre(const parser::DoConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::IfConstruct &construct) { + bool Pre(const parser::IfConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::SelectRankConstruct &construct) { + bool Pre(const parser::SelectRankConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::SelectTypeConstruct &construct) { + bool Pre(const parser::SelectTypeConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::WhereConstruct &construct) { + bool Pre(const parser::WhereConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::ForallConstruct &construct) { + bool Pre(const parser::ForallConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::CompilerDirective &construct) { + bool Pre(const parser::CompilerDirective &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::OpenMPConstruct &construct) { + bool Pre(const parser::OpenMPConstruct &construct) { return enterConstruct(construct); } - bool Pre(const Fortran::parser::OmpEndLoopDirective &construct) { + bool Pre(const parser::OmpEndLoopDirective &construct) { return enterConstruct(construct); } - void Post(const Fortran::parser::AssociateConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::BlockConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::CaseConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::ChangeTeamConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::CriticalConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::DoConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::IfConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::SelectRankConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::SelectTypeConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::WhereConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::ForallConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::CompilerDirective &) { exitConstruct(); } - void Post(const Fortran::parser::OpenMPConstruct &) { exitConstruct(); } - void Post(const Fortran::parser::OmpEndLoopDirective &) { exitConstruct(); } + void Post(const parser::AssociateConstruct &) { exitConstruct(); } + void Post(const parser::BlockConstruct &) { exitConstruct(); } + void Post(const parser::CaseConstruct &) { exitConstruct(); } + void Post(const parser::ChangeTeamConstruct &) { exitConstruct(); } + void Post(const parser::CriticalConstruct &) { exitConstruct(); } + void Post(const parser::DoConstruct &) { exitConstruct(); } + void Post(const parser::IfConstruct &) { exitConstruct(); } + void Post(const parser::SelectRankConstruct &) { exitConstruct(); } + void Post(const parser::SelectTypeConstruct &) { exitConstruct(); } + void Post(const parser::WhereConstruct &) { exitConstruct(); } + void Post(const parser::ForallConstruct &) { exitConstruct(); } + void Post(const parser::CompilerDirective &) { exitConstruct(); } + void Post(const parser::OpenMPConstruct &) { exitConstruct(); } + void Post(const parser::OmpEndLoopDirective &) { exitConstruct(); } private: // ActionStmt has a couple of non-conforming cases, which get handled // explicitly here. The other cases use an Indirection, which we discard in // the AST. - Fortran::lower::AST::Evaluation - makeEvalAction(const Fortran::parser::Statement - &statement) { + AST::Evaluation + makeEvalAction(const parser::Statement &statement) { return std::visit( - Fortran::common::visitors{ - [&](const Fortran::parser::ContinueStmt &x) { - return Fortran::lower::AST::Evaluation{ - x, parents.back(), statement.source, statement.label}; + common::visitors{ + [&](const parser::ContinueStmt &x) { + return AST::Evaluation{x, parents.back(), statement.source, + statement.label}; }, - [&](const Fortran::parser::FailImageStmt &x) { - return Fortran::lower::AST::Evaluation{ - x, parents.back(), statement.source, statement.label}; + [&](const parser::FailImageStmt &x) { + return AST::Evaluation{x, parents.back(), statement.source, + statement.label}; }, [&](const auto &x) { - return Fortran::lower::AST::Evaluation{ - x.value(), parents.back(), statement.source, statement.label}; + return AST::Evaluation{x.value(), parents.back(), + statement.source, statement.label}; }, }, statement.statement.u); } - Fortran::lower::AST::Evaluation makeEvalAction( - const Fortran::parser::UnlabeledStatement - &statement) { + AST::Evaluation makeEvalAction( + const parser::UnlabeledStatement &statement) { return std::visit( - Fortran::common::visitors{ - [&](const Fortran::parser::ContinueStmt &x) { - return Fortran::lower::AST::Evaluation{ - x, parents.back(), statement.source, {}}; + common::visitors{ + [&](const parser::ContinueStmt &x) { + return AST::Evaluation{x, parents.back(), statement.source, {}}; }, - [&](const Fortran::parser::FailImageStmt &x) { - return Fortran::lower::AST::Evaluation{ - x, parents.back(), statement.source, {}}; + [&](const parser::FailImageStmt &x) { + return AST::Evaluation{x, parents.back(), statement.source, {}}; }, [&](const auto &x) { - return Fortran::lower::AST::Evaluation{ + return AST::Evaluation{ x.value(), parents.back(), statement.source, {}}; }, }, @@ -358,27 +310,23 @@ class ASTBuilder { } template - Fortran::lower::AST::Evaluation makeEvalIndirect( - const Fortran::parser::Statement> - &statement) { - return Fortran::lower::AST::Evaluation{statement.statement.value(), - parents.back(), statement.source, - statement.label}; + AST::Evaluation + makeEvalIndirect(const parser::Statement> &statement) { + return AST::Evaluation{statement.statement.value(), parents.back(), + statement.source, statement.label}; } template - Fortran::lower::AST::Evaluation - makeEvalDirect(const Fortran::parser::Statement &statement) { - return Fortran::lower::AST::Evaluation{statement.statement, parents.back(), - statement.source, statement.label}; + AST::Evaluation makeEvalDirect(const parser::Statement &statement) { + return AST::Evaluation{statement.statement, parents.back(), + statement.source, statement.label}; } // When we enter a function-like structure, we want to build a new unit and // set the builder's cursors to point to it. template bool enterFunc(const A &func) { - auto &unit = - addFunc(Fortran::lower::AST::FunctionLikeUnit{func, parents.back()}); + auto &unit = addFunc(AST::FunctionLikeUnit{func, parents.back()}); funclist = &unit.funcs; pushEval(&unit.evals); parents.emplace_back(&unit); @@ -395,9 +343,8 @@ class ASTBuilder { // set the builder's evaluation cursor to point to it. template bool enterConstruct(const A &construct) { - auto &con = - addEval(Fortran::lower::AST::Evaluation{construct, parents.back()}); - con.subs.reset(new Fortran::lower::AST::EvaluationCollection); + auto &con = addEval(AST::Evaluation{construct, parents.back()}); + con.subs.reset(new AST::EvaluationCollection); pushEval(con.subs.get()); parents.emplace_back(&con); return true; @@ -412,8 +359,7 @@ class ASTBuilder { // set the builder's function cursor to point to it. template bool enterModule(const A &func) { - auto &unit = - addUnit(Fortran::lower::AST::ModuleLikeUnit{func, parents.back()}); + auto &unit = addUnit(AST::ModuleLikeUnit{func, parents.back()}); funclist = &unit.funcs; parents.emplace_back(&unit); return true; @@ -440,8 +386,7 @@ class ASTBuilder { } /// move the Evaluation to the end of the current list - Fortran::lower::AST::Evaluation & - addEval(Fortran::lower::AST::Evaluation &&eval) { + AST::Evaluation &addEval(AST::Evaluation &&eval) { assert(funclist && "not in a function"); assert(evallist.size() > 0); evallist.back()->emplace_back(std::move(eval)); @@ -449,7 +394,7 @@ class ASTBuilder { } /// push a new list on the stack of Evaluation lists - void pushEval(Fortran::lower::AST::EvaluationCollection *eval) { + void pushEval(AST::EvaluationCollection *eval) { assert(funclist && "not in a function"); assert(eval && eval->empty() && "evaluation list isn't correct"); evallist.emplace_back(eval); @@ -461,34 +406,33 @@ class ASTBuilder { evallist.pop_back(); } - std::unique_ptr pgm; - std::list *funclist{nullptr}; - std::vector evallist; - std::vector parents; + std::unique_ptr pgm; + std::list *funclist{nullptr}; + std::vector evallist; + std::vector parents; }; template constexpr bool hasErrLabel(const A &stmt) { auto isError{[](const auto &v) { - return std::holds_alternative(v.u); + return std::holds_alternative(v.u); }}; - if constexpr (std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v) { return std::any_of(std::begin(stmt.controls), std::end(stmt.controls), isError); } - if constexpr (std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v) { return std::any_of(std::begin(stmt.v), std::end(stmt.v), isError); } - if constexpr (std::is_same_v) { - const auto &specifiers{ - std::get>(stmt.u)}; + if constexpr (std::is_same_v) { + const auto &specifiers{std::get>(stmt.u)}; return std::any_of(std::begin(specifiers), std::end(specifiers), isError); } return false; @@ -496,16 +440,16 @@ constexpr bool hasErrLabel(const A &stmt) { template constexpr bool hasEorLabel(const A &stmt) { - if constexpr (std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v) { for (const auto &control : stmt.controls) { - if (std::holds_alternative(control.u)) + if (std::holds_alternative(control.u)) return true; } } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { for (const auto &waitSpec : stmt.v) { - if (std::holds_alternative(waitSpec.u)) + if (std::holds_alternative(waitSpec.u)) return true; } } @@ -514,28 +458,27 @@ constexpr bool hasEorLabel(const A &stmt) { template constexpr bool hasEndLabel(const A &stmt) { - if constexpr (std::is_same_v || - std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v) { for (const auto &control : stmt.controls) { - if (std::holds_alternative(control.u)) + if (std::holds_alternative(control.u)) return true; } } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { for (const auto &waitSpec : stmt.v) { - if (std::holds_alternative(waitSpec.u)) + if (std::holds_alternative(waitSpec.u)) return true; } } return false; } -bool hasAltReturns(const Fortran::parser::CallStmt &callStmt) { - const auto &args{ - std::get>(callStmt.v.t)}; +bool hasAltReturns(const parser::CallStmt &callStmt) { + const auto &args{std::get>(callStmt.v.t)}; for (const auto &arg : args) { - const auto &actual{std::get(arg.t)}; - if (std::holds_alternative(actual.u)) + const auto &actual{std::get(arg.t)}; + if (std::holds_alternative(actual.u)) return true; } return false; @@ -543,24 +486,22 @@ bool hasAltReturns(const Fortran::parser::CallStmt &callStmt) { /// Determine if `callStmt` has alternate returns and if so set `e` to be the /// origin of a switch-like control flow -void altRet(Fortran::lower::AST::Evaluation &evaluation, - const Fortran::parser::CallStmt *callStmt, - Fortran::lower::AST::Evaluation *cstr) { +void altRet(AST::Evaluation &evaluation, const parser::CallStmt *callStmt, + AST::Evaluation *cstr) { if (hasAltReturns(*callStmt)) - evaluation.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + evaluation.setCFG(AST::CFGAnnotation::Switch, cstr); } template -void ioLabel(Fortran::lower::AST::Evaluation &evaluation, const A *statement, - Fortran::lower::AST::Evaluation *cstr) { +void ioLabel(AST::Evaluation &evaluation, const A *statement, + AST::Evaluation *cstr) { if (hasErrLabel(*statement) || hasEorLabel(*statement) || hasEndLabel(*statement)) - evaluation.setCFG(Fortran::lower::AST::CFGAnnotation::IoSwitch, cstr); + evaluation.setCFG(AST::CFGAnnotation::IoSwitch, cstr); } -void annotateEvalListCFG( - Fortran::lower::AST::EvaluationCollection &evaluationCollection, - Fortran::lower::AST::Evaluation *cstr) { +void annotateEvalListCFG(AST::EvaluationCollection &evaluationCollection, + AST::Evaluation *cstr) { bool nextIsTarget = false; for (auto &eval : evaluationCollection) { eval.isTarget = nextIsTarget; @@ -573,155 +514,133 @@ void annotateEvalListCFG( if (eval.isActionOrGenerated() && eval.lab.has_value()) eval.isTarget = true; std::visit( - Fortran::common::visitors{ - [&](const Fortran::parser::BackspaceStmt *statement) { + common::visitors{ + [&](const parser::BackspaceStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::CallStmt *statement) { + [&](const parser::CallStmt *statement) { altRet(eval, statement, cstr); }, - [&](const Fortran::parser::CloseStmt *statement) { + [&](const parser::CloseStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::CycleStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + [&](const parser::CycleStmt *) { + eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, - [&](const Fortran::parser::EndfileStmt *statement) { + [&](const parser::EndfileStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::ExitStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + [&](const parser::ExitStmt *) { + eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, - [&](const Fortran::parser::FailImageStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Terminate, cstr); + [&](const parser::FailImageStmt *) { + eval.setCFG(AST::CFGAnnotation::Terminate, cstr); }, - [&](const Fortran::parser::FlushStmt *statement) { + [&](const parser::FlushStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::GotoStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + [&](const parser::GotoStmt *) { + eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, - [&](const Fortran::parser::IfStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); + [&](const parser::IfStmt *) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Fortran::parser::InquireStmt *statement) { + [&](const parser::InquireStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::OpenStmt *statement) { + [&](const parser::OpenStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::ReadStmt *statement) { + [&](const parser::ReadStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::ReturnStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Return, cstr); + [&](const parser::ReturnStmt *) { + eval.setCFG(AST::CFGAnnotation::Return, cstr); }, - [&](const Fortran::parser::RewindStmt *statement) { + [&](const parser::RewindStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::StopStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Terminate, cstr); + [&](const parser::StopStmt *) { + eval.setCFG(AST::CFGAnnotation::Terminate, cstr); }, - [&](const Fortran::parser::WaitStmt *statement) { + [&](const parser::WaitStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::WriteStmt *statement) { + [&](const parser::WriteStmt *statement) { ioLabel(eval, statement, cstr); }, - [&](const Fortran::parser::ArithmeticIfStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + [&](const parser::ArithmeticIfStmt *) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); }, - [&](const Fortran::parser::AssignedGotoStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::IndGoto, cstr); + [&](const parser::AssignedGotoStmt *) { + eval.setCFG(AST::CFGAnnotation::IndGoto, cstr); }, - [&](const Fortran::parser::ComputedGotoStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); + [&](const parser::ComputedGotoStmt *) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); }, - [&](const Fortran::parser::WhereStmt *) { + [&](const parser::WhereStmt *) { // fir.loop + fir.where around the next stmt eval.isTarget = true; - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); }, - [&](const Fortran::parser::ForallStmt *) { + [&](const parser::ForallStmt *) { // fir.loop around the next stmt eval.isTarget = true; - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); - }, - [&](Fortran::lower::AST::CGJump &) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); - }, - [&](const Fortran::parser::EndAssociateStmt *) { - eval.isTarget = true; - }, - [&](const Fortran::parser::EndBlockStmt *) { - eval.isTarget = true; - }, - [&](const Fortran::parser::SelectCaseStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); - }, - [&](const Fortran::parser::CaseStmt *) { eval.isTarget = true; }, - [&](const Fortran::parser::EndSelectStmt *) { + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](AST::CGJump &) { eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, + [&](const parser::EndAssociateStmt *) { eval.isTarget = true; }, + [&](const parser::EndBlockStmt *) { eval.isTarget = true; }, + [&](const parser::SelectCaseStmt *) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const parser::CaseStmt *) { eval.isTarget = true; }, + [&](const parser::EndSelectStmt *) { eval.isTarget = true; }, + [&](const parser::EndChangeTeamStmt *) { eval.isTarget = true; }, + [&](const parser::EndCriticalStmt *) { eval.isTarget = true; }, + [&](const parser::NonLabelDoStmt *) { eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); }, - [&](const Fortran::parser::EndChangeTeamStmt *) { + [&](const parser::EndDoStmt *) { eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, - [&](const Fortran::parser::EndCriticalStmt *) { - eval.isTarget = true; - }, - [&](const Fortran::parser::NonLabelDoStmt *) { - eval.isTarget = true; - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); + [&](const parser::IfThenStmt *) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Fortran::parser::EndDoStmt *) { - eval.isTarget = true; - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Goto, cstr); + [&](const parser::ElseIfStmt *) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Fortran::parser::IfThenStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); + [&](const parser::ElseStmt *) { eval.isTarget = true; }, + [&](const parser::EndIfStmt *) { eval.isTarget = true; }, + [&](const parser::SelectRankStmt *) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); }, - [&](const Fortran::parser::ElseIfStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const Fortran::parser::ElseStmt *) { eval.isTarget = true; }, - [&](const Fortran::parser::EndIfStmt *) { eval.isTarget = true; }, - [&](const Fortran::parser::SelectRankStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); - }, - [&](const Fortran::parser::SelectRankCaseStmt *) { - eval.isTarget = true; + [&](const parser::SelectRankCaseStmt *) { eval.isTarget = true; }, + [&](const parser::SelectTypeStmt *) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); }, - [&](const Fortran::parser::SelectTypeStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Switch, cstr); - }, - [&](const Fortran::parser::TypeGuardStmt *) { - eval.isTarget = true; - }, - [&](const Fortran::parser::WhereConstruct *) { + [&](const parser::TypeGuardStmt *) { eval.isTarget = true; }, + [&](const parser::WhereConstruct *) { // mark the WHERE as if it were a DO loop eval.isTarget = true; - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); - }, - [&](const Fortran::parser::WhereConstructStmt *) { - eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); }, - [&](const Fortran::parser::MaskedElsewhereStmt *) { - eval.isTarget = true; - eval.setCFG(Fortran::lower::AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const Fortran::parser::ElsewhereStmt *) { - eval.isTarget = true; + [&](const parser::WhereConstructStmt *) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Fortran::parser::EndWhereStmt *) { + [&](const parser::MaskedElsewhereStmt *) { eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); }, - [&](const Fortran::parser::ForallConstructStmt *) { - eval.isTarget = true; - eval.setCFG(Fortran::lower::AST::CFGAnnotation::Iterative, cstr); - }, - [&](const Fortran::parser::EndForallStmt *) { + [&](const parser::ElsewhereStmt *) { eval.isTarget = true; }, + [&](const parser::EndWhereStmt *) { eval.isTarget = true; }, + [&](const parser::ForallConstructStmt *) { eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); }, + [&](const parser::EndForallStmt *) { eval.isTarget = true; }, [](const auto *) { /* do nothing */ }, }, eval.u); @@ -730,30 +649,27 @@ void annotateEvalListCFG( /// Annotate the AST with CFG source decorations (see CFGAnnotation) and mark /// potential branch targets -inline void -annotateFuncCFG(Fortran::lower::AST::FunctionLikeUnit &functionLikeUnit) { +inline void annotateFuncCFG(AST::FunctionLikeUnit &functionLikeUnit) { annotateEvalListCFG(functionLikeUnit.evals, nullptr); } -llvm::StringRef evalName(Fortran::lower::AST::Evaluation &eval) { +llvm::StringRef evalName(AST::Evaluation &eval) { return std::visit( - Fortran::common::visitors{ - [](const Fortran::lower::AST::CGJump) { return "CGJump"; }, - [](const auto *parseTreeNode) { - assert(parseTreeNode && "nullptr node in AST "); - return Fortran::parser::ParseTreeDumper::GetNodeName( - *parseTreeNode); - }}, + common::visitors{[](const AST::CGJump) { return "CGJump"; }, + [](const auto *parseTreeNode) { + assert(parseTreeNode && "nullptr node in AST "); + return parser::ParseTreeDumper::GetNodeName( + *parseTreeNode); + }}, eval.u); } -void dumpEvalList( - llvm::raw_ostream &outputStream, - Fortran::lower::AST::EvaluationCollection &evaluationCollection, - int indent = 1) { +void dumpEvalList(llvm::raw_ostream &outputStream, + AST::EvaluationCollection &evaluationCollection, + int indent = 1) { static const std::string white{" ++"}; std::string indentString{white.substr(0, indent * 2)}; - for (Fortran::lower::AST::Evaluation &eval : evaluationCollection) { + for (AST::Evaluation &eval : evaluationCollection) { llvm::StringRef name{evalName(eval)}; if (eval.isConstruct()) { outputStream << indentString << "<<" << name << ">>\n"; @@ -766,42 +682,34 @@ void dumpEvalList( } } -void dumpFunctionLikeUnit( - llvm::raw_ostream &outputStream, - Fortran::lower::AST::FunctionLikeUnit &functionLikeUnit) { +void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, + AST::FunctionLikeUnit &functionLikeUnit) { llvm::StringRef unitKind{}; std::string name{}; std::string header{}; std::visit( - Fortran::common::visitors{ - [&](const Fortran::parser::Statement - *statement) { + common::visitors{ + [&](const parser::Statement *statement) { unitKind = "Program"; name = statement->statement.v.ToString(); }, - [&](const Fortran::parser::Statement - *statement) { + [&](const parser::Statement *statement) { unitKind = "Function"; - name = std::get(statement->statement.t) - .ToString(); + name = std::get(statement->statement.t).ToString(); header = statement->source.ToString(); }, - [&](const Fortran::parser::Statement - *statement) { + [&](const parser::Statement *statement) { unitKind = "Subroutine"; - name = std::get(statement->statement.t) - .ToString(); + name = std::get(statement->statement.t).ToString(); header = statement->source.ToString(); }, - [&](const Fortran::parser::Statement< - Fortran::parser::MpSubprogramStmt> *statement) { + [&](const parser::Statement *statement) { unitKind = "MpSubprogram"; name = statement->statement.v.ToString(); header = statement->source.ToString(); }, [&](auto *) { - if (std::get_if *>( + if (std::get_if *>( &functionLikeUnit.funStmts.back())) { unitKind = "Program"; name = ""; @@ -821,106 +729,82 @@ void dumpFunctionLikeUnit( } // namespace -Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( - const Fortran::parser::MainProgram &func, - const Fortran::lower::AST::ParentType &parent) +AST::FunctionLikeUnit::FunctionLikeUnit(const parser::MainProgram &func, + const AST::ParentType &parent) : ProgramUnit{&func, parent} { - auto &ps{std::get< - std::optional>>( - func.t)}; + auto &ps{ + std::get>>(func.t)}; if (ps.has_value()) { - const Fortran::parser::Statement &statement{ - ps.value()}; + const parser::Statement &statement{ps.value()}; funStmts.push_back(&statement); } funStmts.push_back( - &std::get>( - func.t)); + &std::get>(func.t)); } -Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( - const Fortran::parser::FunctionSubprogram &func, - const Fortran::lower::AST::ParentType &parent) +AST::FunctionLikeUnit::FunctionLikeUnit(const parser::FunctionSubprogram &func, + const AST::ParentType &parent) : ProgramUnit{&func, parent} { funStmts.push_back( - &std::get>( - func.t)); + &std::get>(func.t)); funStmts.push_back( - &std::get>( - func.t)); + &std::get>(func.t)); } -Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( - const Fortran::parser::SubroutineSubprogram &func, - const Fortran::lower::AST::ParentType &parent) +AST::FunctionLikeUnit::FunctionLikeUnit( + const parser::SubroutineSubprogram &func, const AST::ParentType &parent) : ProgramUnit{&func, parent} { funStmts.push_back( - &std::get>( - func.t)); + &std::get>(func.t)); funStmts.push_back( - &std::get>( - func.t)); + &std::get>(func.t)); } -Fortran::lower::AST::FunctionLikeUnit::FunctionLikeUnit( - const Fortran::parser::SeparateModuleSubprogram &func, - const Fortran::lower::AST::ParentType &parent) +AST::FunctionLikeUnit::FunctionLikeUnit( + const parser::SeparateModuleSubprogram &func, const AST::ParentType &parent) : ProgramUnit{&func, parent} { funStmts.push_back( - &std::get>( - func.t)); + &std::get>(func.t)); funStmts.push_back( - &std::get< - Fortran::parser::Statement>( - func.t)); + &std::get>(func.t)); } -Fortran::lower::AST::ModuleLikeUnit::ModuleLikeUnit( - const Fortran::parser::Module &m, - const Fortran::lower::AST::ParentType &parent) +AST::ModuleLikeUnit::ModuleLikeUnit(const parser::Module &m, + const AST::ParentType &parent) : ProgramUnit{&m, parent} { - modStmts.push_back( - &std::get>(m.t)); - modStmts.push_back( - &std::get>( - m.t)); + modStmts.push_back(&std::get>(m.t)); + modStmts.push_back(&std::get>(m.t)); } -Fortran::lower::AST::ModuleLikeUnit::ModuleLikeUnit( - const Fortran::parser::Submodule &m, - const Fortran::lower::AST::ParentType &parent) +AST::ModuleLikeUnit::ModuleLikeUnit(const parser::Submodule &m, + const AST::ParentType &parent) : ProgramUnit{&m, parent} { + modStmts.push_back(&std::get>(m.t)); modStmts.push_back( - &std::get>( - m.t)); - modStmts.push_back( - &std::get>( - m.t)); + &std::get>(m.t)); } -Fortran::lower::AST::BlockDataUnit::BlockDataUnit( - const Fortran::parser::BlockData &bd, - const Fortran::lower::AST::ParentType &parent) +AST::BlockDataUnit::BlockDataUnit(const parser::BlockData &bd, + const AST::ParentType &parent) : ProgramUnit{&bd, parent} {} -std::unique_ptr -Fortran::lower::createAST(const Fortran::parser::Program &root) { +std::unique_ptr createAST(const parser::Program &root) { ASTBuilder walker; Walk(root, walker); return walker.result(); } -void Fortran::lower::annotateControl(Fortran::lower::AST::Program &ast) { +void annotateControl(AST::Program &ast) { for (auto &unit : ast.getUnits()) { - std::visit(Fortran::common::visitors{ - [](Fortran::lower::AST::BlockDataUnit &) {}, - [](Fortran::lower::AST::FunctionLikeUnit &func) { + std::visit(common::visitors{ + [](AST::BlockDataUnit &) {}, + [](AST::FunctionLikeUnit &func) { annotateFuncCFG(func); for (auto &statement : func.funcs) { annotateFuncCFG(statement); } }, - [](Fortran::lower::AST::ModuleLikeUnit &unit) { + [](AST::ModuleLikeUnit &unit) { for (auto &func : unit.funcs) { annotateFuncCFG(func); } @@ -931,20 +815,19 @@ void Fortran::lower::annotateControl(Fortran::lower::AST::Program &ast) { } /// Dump an AST. -void Fortran::lower::dumpAST(llvm::raw_ostream &outputStream, - Fortran::lower::AST::Program &ast) { +void dumpAST(llvm::raw_ostream &outputStream, AST::Program &ast) { for (auto &unit : ast.getUnits()) { - std::visit(Fortran::common::visitors{ - [&](Fortran::lower::AST::BlockDataUnit &) { + std::visit(common::visitors{ + [&](AST::BlockDataUnit &) { outputStream << "BlockData\nEndBlockData\n\n"; }, - [&](Fortran::lower::AST::FunctionLikeUnit &func) { + [&](AST::FunctionLikeUnit &func) { dumpFunctionLikeUnit(outputStream, func); for (auto &func : func.funcs) { dumpFunctionLikeUnit(outputStream, func); } }, - [&](Fortran::lower::AST::ModuleLikeUnit &unit) { + [&](AST::ModuleLikeUnit &unit) { for (auto &func : unit.funcs) { dumpFunctionLikeUnit(outputStream, func); } @@ -953,3 +836,5 @@ void Fortran::lower::dumpAST(llvm::raw_ostream &outputStream, unit); } } + +} // namespace Fortran::lower From 16ab9dacd8993694ace6c1c85dd8a4763ba89c21 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Fri, 31 Jan 2020 04:21:23 -0800 Subject: [PATCH 10/24] [review 959] Fix file name in copyright and add/update comments --- include/flang/lower/ASTBuilder.h | 38 ++++++++++++++++++++++---------- lib/lower/ASTBuilder.cpp | 18 ++++++--------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 3f1dc1ad1bea..14d29eba2c07 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -1,4 +1,4 @@ -//===-- include/flang/lower/AstBuilder.h ------------------------*- C++ -*-===// +//===-- include/flang/lower/ASTBuilder.h ------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -14,6 +14,16 @@ #include "llvm/Support/raw_ostream.h" #include +/// Build a light-weight AST to help with lowering to FIR. The AST will +/// capture pointers back into the parse tree, so the parse tree data structure +/// may not be changed between the construction of the AST and all of +/// its uses. +/// +/// The AST captures a structured view of the program. The program is a list of +/// units. Function like units will contain lists of evaluations. Evaluations +/// are either statements or constructs, where a construct contains a list of +/// evaluations. The resulting AST structure can then be used to create FIR. + namespace Fortran::lower { namespace AST { @@ -30,17 +40,20 @@ using EvaluationCollection = std::list; using ParentType = std::variant; +/// Flags to describe the impact of parse-trees nodes on the program +/// control flow. These annotations to parse-tree nodes are later used to +/// build the control flow graph when lowering to FIR. enum class CFGAnnotation { - None, - Goto, - CondGoto, - IndGoto, - IoSwitch, - Switch, - Iterative, - FirStructuredOp, - Return, - Terminate + None, // Node does not impact control flow. + Goto, // Node acts like a goto on the control flow. + CondGoto, // Node acts like a conditional goto on the control flow. + IndGoto, // Node acts like an indirect goto on the control flow. + IoSwitch, // Node is an IO statement with ERR, END, or EOR specifier. + Switch, // Node acts like a switch on the control flow. + Iterative, // Node creates iterations in the control flow. + FirStructuredOp, // Node is a structured loop. + Return, // Node triggers a return from the current procedure. + Terminate // Node terminates the program. }; /// Compiler-generated jump @@ -240,7 +253,8 @@ struct ProgramUnit { }; /// Function-like units have similar structure. They all can contain executable -/// statements. +/// statements as well as other function-like units (internal procedures and +/// function statements). struct FunctionLikeUnit : public ProgramUnit { // wrapper statements for function-like syntactic structures using FunctionStatement = diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index fff32f7493d9..57e55fdbff56 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -1,4 +1,4 @@ -//===-- lib/lower/AstBuilder.cc -------------------------------------------===// +//===-- lib/lower/ASTBuilder.cc -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,16 +13,6 @@ #include #include -/// Build a light-weight AST to help with lowering to FIR. The AST will -/// capture pointers back into the parse tree, so the parse tree data structure -/// may not be changed between the construction of the AST and all of -/// its uses. -/// -/// The AST captures a structured view of the program. The program is a list of -/// units. Function like units will contain lists of evaluations. Evaluations -/// are either statements or constructs, where a construct contains a list of -/// evaluations. The resulting AST structure can then be used to create FIR. - namespace Fortran::lower { namespace { @@ -407,7 +397,13 @@ class ASTBuilder { } std::unique_ptr pgm; + /// funclist points to FunctionLikeUnit::funcs list (resp. + /// ModuleLikeUnit::funcs) when building a FunctionLikeUnit (resp. + /// ModuleLikeUnit) to store internal procedures (resp. module procedures). + /// Otherwise (e.g. when building the top level Program), it is null. std::list *funclist{nullptr}; + /// evallist is a stack of pointer to FunctionLikeUnit::evals (or + /// Evaluation::subs) that are being build. std::vector evallist; std::vector parents; }; From 32f77b68fc5f66775d6893e66ae803e3fea0cf93 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Fri, 31 Jan 2020 04:49:38 -0800 Subject: [PATCH 11/24] [review 959] add comment regarding cstr argument --- lib/lower/ASTBuilder.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index 57e55fdbff56..ab03c3ac49f6 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -482,6 +482,9 @@ bool hasAltReturns(const parser::CallStmt &callStmt) { /// Determine if `callStmt` has alternate returns and if so set `e` to be the /// origin of a switch-like control flow +/// +/// \param cstr points to the current construct. It may be null at the top-level +/// of a FunctionLikeUnit. void altRet(AST::Evaluation &evaluation, const parser::CallStmt *callStmt, AST::Evaluation *cstr) { if (hasAltReturns(*callStmt)) @@ -496,6 +499,8 @@ void ioLabel(AST::Evaluation &evaluation, const A *statement, evaluation.setCFG(AST::CFGAnnotation::IoSwitch, cstr); } +/// \param cstr points to the current construct. It may be null at the top-level +/// of a FunctionLikeUnit. void annotateEvalListCFG(AST::EvaluationCollection &evaluationCollection, AST::Evaluation *cstr) { bool nextIsTarget = false; From b40032345b06818bdde3d4eae62aaf1632a66381 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Fri, 31 Jan 2020 05:10:31 -0800 Subject: [PATCH 12/24] [review 959] Remove unused scope members. Make CGJump::target a reference. --- include/flang/lower/ASTBuilder.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 14d29eba2c07..3f600beb438c 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -10,7 +10,6 @@ #define FORTRAN_LOWER_AST_BUILDER_H_ #include "flang/parser/parse-tree.h" -#include "flang/semantics/scope.h" #include "llvm/Support/raw_ostream.h" #include @@ -61,8 +60,8 @@ enum class CFGAnnotation { /// This is used to convert implicit control-flow edges to explicit form in the /// decorated AST struct CGJump { - CGJump(Evaluation *to) : target{to} {} - Evaluation *target{nullptr}; + CGJump(Evaluation &to) : target{to} {} + Evaluation ⌖ }; /// is `A` a construct (or directive)? @@ -291,10 +290,9 @@ struct FunctionLikeUnit : public ProgramUnit { return getA(); } - const semantics::Scope *scope{nullptr}; // scope from front-end - std::list funStmts; // begin/end pair - EvaluationCollection evals; // statements - std::list funcs; // internal procedures + std::list funStmts; // begin/end pair + EvaluationCollection evals; // statements + std::list funcs; // internal procedures private: template @@ -321,7 +319,6 @@ struct ModuleLikeUnit : public ProgramUnit { ModuleLikeUnit(ModuleLikeUnit &&) = default; ModuleLikeUnit(const ModuleLikeUnit &) = delete; - const semantics::Scope *scope{nullptr}; std::list modStmts; std::list funcs; }; From 02e4c145b81e18ae8a861ffeecd50a86a59aef90 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Fri, 31 Jan 2020 10:30:07 -0800 Subject: [PATCH 13/24] [review 959] Change parse tree node classification and hide pointers --- include/flang/lower/ASTBuilder.h | 197 +++++++++++---------- lib/lower/ASTBuilder.cpp | 282 +++++++++++++++---------------- 2 files changed, 237 insertions(+), 242 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 3f600beb438c..18bd5d23faca 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -9,6 +9,7 @@ #ifndef FORTRAN_LOWER_AST_BUILDER_H_ #define FORTRAN_LOWER_AST_BUILDER_H_ +#include "flang/common/template.h" #include "flang/parser/parse-tree.h" #include "llvm/Support/raw_ostream.h" #include @@ -64,80 +65,98 @@ struct CGJump { Evaluation ⌖ }; +/// Classify the parse-tree nodes from ExecutablePartConstruct + +using ActionStmts = std::tuple< + parser::AllocateStmt, parser::AssignmentStmt, parser::BackspaceStmt, + parser::CallStmt, parser::CloseStmt, parser::ContinueStmt, + parser::CycleStmt, parser::DeallocateStmt, parser::EndfileStmt, + parser::EventPostStmt, parser::EventWaitStmt, parser::ExitStmt, + parser::FailImageStmt, parser::FlushStmt, parser::FormTeamStmt, + parser::GotoStmt, parser::IfStmt, parser::InquireStmt, parser::LockStmt, + parser::NullifyStmt, parser::OpenStmt, parser::PointerAssignmentStmt, + parser::PrintStmt, parser::ReadStmt, parser::ReturnStmt, parser::RewindStmt, + parser::StopStmt, parser::SyncAllStmt, parser::SyncImagesStmt, + parser::SyncMemoryStmt, parser::SyncTeamStmt, parser::UnlockStmt, + parser::WaitStmt, parser::WhereStmt, parser::WriteStmt, + parser::ComputedGotoStmt, parser::ForallStmt, parser::ArithmeticIfStmt, + parser::AssignStmt, parser::AssignedGotoStmt, parser::PauseStmt>; + +using OtherStmts = std::tuple; + +using Constructs = + std::tuple; + +using ConstructStmts = std::tuple< + parser::AssociateStmt, parser::EndAssociateStmt, parser::BlockStmt, + parser::EndBlockStmt, parser::SelectCaseStmt, parser::CaseStmt, + parser::EndSelectStmt, parser::ChangeTeamStmt, parser::EndChangeTeamStmt, + parser::CriticalStmt, parser::EndCriticalStmt, parser::NonLabelDoStmt, + parser::EndDoStmt, parser::IfThenStmt, parser::ElseIfStmt, parser::ElseStmt, + parser::EndIfStmt, parser::SelectRankStmt, parser::SelectRankCaseStmt, + parser::SelectTypeStmt, parser::TypeGuardStmt, parser::WhereConstructStmt, + parser::MaskedElsewhereStmt, parser::ElsewhereStmt, parser::EndWhereStmt, + parser::ForallConstructStmt, parser::EndForallStmt>; + /// is `A` a construct (or directive)? template -constexpr static bool isConstruct() { - return std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; -} +constexpr static bool isConstruct{common::HasMember}; + +template +constexpr static bool isOtherStmt{common::HasMember}; + +template +constexpr static bool isActionStmt{common::HasMember}; + +template +constexpr static bool isGenerated{std::is_same_v}; /// Function-like units can contains lists of evaluations. These can be /// (simple) statements or constructs, where a construct contains its own /// evaluations. struct Evaluation { - using EvalVariant = std::variant< - // action statements - const parser::AllocateStmt *, const parser::AssignmentStmt *, - const parser::BackspaceStmt *, const parser::CallStmt *, - const parser::CloseStmt *, const parser::ContinueStmt *, - const parser::CycleStmt *, const parser::DeallocateStmt *, - const parser::EndfileStmt *, const parser::EventPostStmt *, - const parser::EventWaitStmt *, const parser::ExitStmt *, - const parser::FailImageStmt *, const parser::FlushStmt *, - const parser::FormTeamStmt *, const parser::GotoStmt *, - const parser::IfStmt *, const parser::InquireStmt *, - const parser::LockStmt *, const parser::NullifyStmt *, - const parser::OpenStmt *, const parser::PointerAssignmentStmt *, - const parser::PrintStmt *, const parser::ReadStmt *, - const parser::ReturnStmt *, const parser::RewindStmt *, - const parser::StopStmt *, const parser::SyncAllStmt *, - const parser::SyncImagesStmt *, const parser::SyncMemoryStmt *, - const parser::SyncTeamStmt *, const parser::UnlockStmt *, - const parser::WaitStmt *, const parser::WhereStmt *, - const parser::WriteStmt *, const parser::ComputedGotoStmt *, - const parser::ForallStmt *, const parser::ArithmeticIfStmt *, - const parser::AssignStmt *, const parser::AssignedGotoStmt *, - const parser::PauseStmt *, - // compiler generated ops - CGJump, - // other statements - const parser::FormatStmt *, const parser::EntryStmt *, - const parser::DataStmt *, const parser::NamelistStmt *, - // constructs - const parser::AssociateConstruct *, const parser::BlockConstruct *, - const parser::CaseConstruct *, const parser::ChangeTeamConstruct *, - const parser::CriticalConstruct *, const parser::DoConstruct *, - const parser::IfConstruct *, const parser::SelectRankConstruct *, - const parser::SelectTypeConstruct *, const parser::WhereConstruct *, - const parser::ForallConstruct *, const parser::CompilerDirective *, - const parser::OpenMPConstruct *, const parser::OmpEndLoopDirective *, - // construct statements - const parser::AssociateStmt *, const parser::EndAssociateStmt *, - const parser::BlockStmt *, const parser::EndBlockStmt *, - const parser::SelectCaseStmt *, const parser::CaseStmt *, - const parser::EndSelectStmt *, const parser::ChangeTeamStmt *, - const parser::EndChangeTeamStmt *, const parser::CriticalStmt *, - const parser::EndCriticalStmt *, const parser::NonLabelDoStmt *, - const parser::EndDoStmt *, const parser::IfThenStmt *, - const parser::ElseIfStmt *, const parser::ElseStmt *, - const parser::EndIfStmt *, const parser::SelectRankStmt *, - const parser::SelectRankCaseStmt *, const parser::SelectTypeStmt *, - const parser::TypeGuardStmt *, const parser::WhereConstructStmt *, - const parser::MaskedElsewhereStmt *, const parser::ElsewhereStmt *, - const parser::EndWhereStmt *, const parser::ForallConstructStmt *, - const parser::EndForallStmt *>; + using EvalTuple = common::CombineTuples; + + /// Hide the non-nullable pointers to the parse-tree node. + template + using MakeRefType = const A *const; + using EvalVariant = + common::CombineVariants, + std::variant>; + template + constexpr auto visit(T visitor) const { + return std::visit(common::visitors{ + [&](const auto *p) { return visitor(*p); }, + [&](auto &r) { return visitor(r); }, + }, + u); + } + template + constexpr const A *getIf() const { + if constexpr (!std::is_same_v) { + if (auto *ptr{std::get_if>(&u)}) { + return *ptr; + } + } else { + return std::get_if(&u); + } + return nullptr; + } + template + constexpr bool isA() const { + if constexpr (!std::is_same_v) { + return std::holds_alternative>(u); + } + return std::holds_alternative(u); + } Evaluation() = delete; Evaluation(const Evaluation &) = delete; @@ -156,45 +175,25 @@ struct Evaluation { /// Construct ctor template Evaluation(const A &a, const ParentType &parent) : u{&a}, parent{parent} { - static_assert(AST::isConstruct(), "must be a construct"); - } - - /// is `A` an action statement ? - template - constexpr static bool isActionStmt(const A &a) { - return !AST::isConstruct() && !isOther(a); - } - - /// is `A` a compiler-generated evaluation? - template - constexpr static bool isGenerated(const A &) { - return std::is_same_v; - } - - /// is `A` not an executable statement? - template - constexpr static bool isOther(const A &) { - return std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; + static_assert(AST::isConstruct, "must be a construct"); } constexpr bool isActionOrGenerated() const { - return std::visit(common::visitors{ - [](auto *p) { return isActionStmt(*p); }, - [](auto &r) { return isGenerated(r); }, - }, - u); + return visit(common::visitors{ + [](auto &r) { + using T = std::decay_t; + return isActionStmt || isGenerated; + }, + }); } constexpr bool isStmt() const { - return std::visit( - common::visitors{ - [](auto *p) { return isActionStmt(*p) || isOther(*p); }, - [](auto &r) { return isGenerated(r); }, + return visit(common::visitors{ + [](auto &r) { + using T = std::decay_t; + return isActionStmt || isOtherStmt; }, - u); + }); } constexpr bool isConstruct() const { return !isStmt(); } diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index ab03c3ac49f6..246ba8fee946 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -485,17 +485,17 @@ bool hasAltReturns(const parser::CallStmt &callStmt) { /// /// \param cstr points to the current construct. It may be null at the top-level /// of a FunctionLikeUnit. -void altRet(AST::Evaluation &evaluation, const parser::CallStmt *callStmt, +void altRet(AST::Evaluation &evaluation, const parser::CallStmt &callStmt, AST::Evaluation *cstr) { - if (hasAltReturns(*callStmt)) + if (hasAltReturns(callStmt)) evaluation.setCFG(AST::CFGAnnotation::Switch, cstr); } template -void ioLabel(AST::Evaluation &evaluation, const A *statement, +void ioLabel(AST::Evaluation &evaluation, const A &statement, AST::Evaluation *cstr) { - if (hasErrLabel(*statement) || hasEorLabel(*statement) || - hasEndLabel(*statement)) + if (hasErrLabel(statement) || hasEorLabel(statement) || + hasEndLabel(statement)) evaluation.setCFG(AST::CFGAnnotation::IoSwitch, cstr); } @@ -514,137 +514,135 @@ void annotateEvalListCFG(AST::EvaluationCollection &evaluationCollection, } if (eval.isActionOrGenerated() && eval.lab.has_value()) eval.isTarget = true; - std::visit( - common::visitors{ - [&](const parser::BackspaceStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::CallStmt *statement) { - altRet(eval, statement, cstr); - }, - [&](const parser::CloseStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::CycleStmt *) { - eval.setCFG(AST::CFGAnnotation::Goto, cstr); - }, - [&](const parser::EndfileStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::ExitStmt *) { - eval.setCFG(AST::CFGAnnotation::Goto, cstr); - }, - [&](const parser::FailImageStmt *) { - eval.setCFG(AST::CFGAnnotation::Terminate, cstr); - }, - [&](const parser::FlushStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::GotoStmt *) { - eval.setCFG(AST::CFGAnnotation::Goto, cstr); - }, - [&](const parser::IfStmt *) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const parser::InquireStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::OpenStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::ReadStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::ReturnStmt *) { - eval.setCFG(AST::CFGAnnotation::Return, cstr); - }, - [&](const parser::RewindStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::StopStmt *) { - eval.setCFG(AST::CFGAnnotation::Terminate, cstr); - }, - [&](const parser::WaitStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::WriteStmt *statement) { - ioLabel(eval, statement, cstr); - }, - [&](const parser::ArithmeticIfStmt *) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const parser::AssignedGotoStmt *) { - eval.setCFG(AST::CFGAnnotation::IndGoto, cstr); - }, - [&](const parser::ComputedGotoStmt *) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const parser::WhereStmt *) { - // fir.loop + fir.where around the next stmt - eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); - }, - [&](const parser::ForallStmt *) { - // fir.loop around the next stmt - eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); - }, - [&](AST::CGJump &) { eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, - [&](const parser::EndAssociateStmt *) { eval.isTarget = true; }, - [&](const parser::EndBlockStmt *) { eval.isTarget = true; }, - [&](const parser::SelectCaseStmt *) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const parser::CaseStmt *) { eval.isTarget = true; }, - [&](const parser::EndSelectStmt *) { eval.isTarget = true; }, - [&](const parser::EndChangeTeamStmt *) { eval.isTarget = true; }, - [&](const parser::EndCriticalStmt *) { eval.isTarget = true; }, - [&](const parser::NonLabelDoStmt *) { - eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); - }, - [&](const parser::EndDoStmt *) { - eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Goto, cstr); - }, - [&](const parser::IfThenStmt *) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const parser::ElseIfStmt *) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const parser::ElseStmt *) { eval.isTarget = true; }, - [&](const parser::EndIfStmt *) { eval.isTarget = true; }, - [&](const parser::SelectRankStmt *) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const parser::SelectRankCaseStmt *) { eval.isTarget = true; }, - [&](const parser::SelectTypeStmt *) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); - }, - [&](const parser::TypeGuardStmt *) { eval.isTarget = true; }, - [&](const parser::WhereConstruct *) { - // mark the WHERE as if it were a DO loop - eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); - }, - [&](const parser::WhereConstructStmt *) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const parser::MaskedElsewhereStmt *) { - eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); - }, - [&](const parser::ElsewhereStmt *) { eval.isTarget = true; }, - [&](const parser::EndWhereStmt *) { eval.isTarget = true; }, - [&](const parser::ForallConstructStmt *) { - eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); - }, - [&](const parser::EndForallStmt *) { eval.isTarget = true; }, - [](const auto *) { /* do nothing */ }, + eval.visit(common::visitors{ + [&](const parser::BackspaceStmt &statement) { + ioLabel(eval, statement, cstr); }, - eval.u); + [&](const parser::CallStmt &statement) { + altRet(eval, statement, cstr); + }, + [&](const parser::CloseStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::CycleStmt &) { + eval.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const parser::EndfileStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::ExitStmt &) { + eval.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const parser::FailImageStmt &) { + eval.setCFG(AST::CFGAnnotation::Terminate, cstr); + }, + [&](const parser::FlushStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::GotoStmt &) { + eval.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const parser::IfStmt &) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const parser::InquireStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::OpenStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::ReadStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::ReturnStmt &) { + eval.setCFG(AST::CFGAnnotation::Return, cstr); + }, + [&](const parser::RewindStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::StopStmt &) { + eval.setCFG(AST::CFGAnnotation::Terminate, cstr); + }, + [&](const parser::WaitStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::WriteStmt &statement) { + ioLabel(eval, statement, cstr); + }, + [&](const parser::ArithmeticIfStmt &) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const parser::AssignedGotoStmt &) { + eval.setCFG(AST::CFGAnnotation::IndGoto, cstr); + }, + [&](const parser::ComputedGotoStmt &) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const parser::WhereStmt &) { + // fir.loop + fir.where around the next stmt + eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const parser::ForallStmt &) { + // fir.loop around the next stmt + eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](AST::CGJump &) { eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, + [&](const parser::EndAssociateStmt &) { eval.isTarget = true; }, + [&](const parser::EndBlockStmt &) { eval.isTarget = true; }, + [&](const parser::SelectCaseStmt &) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const parser::CaseStmt &) { eval.isTarget = true; }, + [&](const parser::EndSelectStmt &) { eval.isTarget = true; }, + [&](const parser::EndChangeTeamStmt &) { eval.isTarget = true; }, + [&](const parser::EndCriticalStmt &) { eval.isTarget = true; }, + [&](const parser::NonLabelDoStmt &) { + eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const parser::EndDoStmt &) { + eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Goto, cstr); + }, + [&](const parser::IfThenStmt &) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const parser::ElseIfStmt &) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const parser::ElseStmt &) { eval.isTarget = true; }, + [&](const parser::EndIfStmt &) { eval.isTarget = true; }, + [&](const parser::SelectRankStmt &) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const parser::SelectRankCaseStmt &) { eval.isTarget = true; }, + [&](const parser::SelectTypeStmt &) { + eval.setCFG(AST::CFGAnnotation::Switch, cstr); + }, + [&](const parser::TypeGuardStmt &) { eval.isTarget = true; }, + [&](const parser::WhereConstruct &) { + // mark the WHERE as if it were a DO loop + eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const parser::WhereConstructStmt &) { + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const parser::MaskedElsewhereStmt &) { + eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + }, + [&](const parser::ElsewhereStmt &) { eval.isTarget = true; }, + [&](const parser::EndWhereStmt &) { eval.isTarget = true; }, + [&](const parser::ForallConstructStmt &) { + eval.isTarget = true; + eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + }, + [&](const parser::EndForallStmt &) { eval.isTarget = true; }, + [](const auto &) { /* do nothing */ }, + }); } } @@ -655,14 +653,12 @@ inline void annotateFuncCFG(AST::FunctionLikeUnit &functionLikeUnit) { } llvm::StringRef evalName(AST::Evaluation &eval) { - return std::visit( - common::visitors{[](const AST::CGJump) { return "CGJump"; }, - [](const auto *parseTreeNode) { - assert(parseTreeNode && "nullptr node in AST "); - return parser::ParseTreeDumper::GetNodeName( - *parseTreeNode); - }}, - eval.u); + return eval.visit(common::visitors{ + [](const AST::CGJump) { return "CGJump"; }, + [](const auto &parseTreeNode) { + return parser::ParseTreeDumper::GetNodeName(parseTreeNode); + }, + }); } void dumpEvalList(llvm::raw_ostream &outputStream, From b66c4197c3ff059c5ba7e907e57f979fd9dbe06b Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Mon, 3 Feb 2020 06:03:38 -0800 Subject: [PATCH 14/24] [review 959] Protect ParentType and ProgramUnit pointers --- include/flang/lower/ASTBuilder.h | 28 +++++++++++++++++----------- lib/lower/ASTBuilder.cpp | 22 +++++++++++----------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index 18bd5d23faca..e04122b87693 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -37,8 +37,13 @@ struct FunctionLikeUnit; // insert AST nodes in any order in O(1) time. using EvaluationCollection = std::list; -using ParentType = - std::variant; +struct ParentType { + template + ParentType(A &parent) : p{&parent} {} + const std::variant + p; +}; /// Flags to describe the impact of parse-trees nodes on the program /// control flow. These annotations to parse-tree nodes are later used to @@ -125,14 +130,14 @@ struct Evaluation { using EvalTuple = common::CombineTuples; - /// Hide the non-nullable pointers to the parse-tree node. + /// Hide non-nullable pointers to the parse-tree node. template using MakeRefType = const A *const; using EvalVariant = common::CombineVariants, std::variant>; - template - constexpr auto visit(T visitor) const { + template + constexpr auto visit(A visitor) const { return std::visit(common::visitors{ [&](const auto *p) { return visitor(*p); }, [&](auto &r) { return visitor(r); }, @@ -237,15 +242,16 @@ struct Evaluation { /// These units can be function like, module like, or block data struct ProgramUnit { template - ProgramUnit(A *ptr, const ParentType &parent) : p{ptr}, parent{parent} {} + ProgramUnit(const A &ptr, const ParentType &parent) + : p{&ptr}, parent{parent} {} ProgramUnit(ProgramUnit &&) = default; ProgramUnit(const ProgramUnit &) = delete; - std::variant + const std::variant< + const parser::MainProgram *, const parser::FunctionSubprogram *, + const parser::SubroutineSubprogram *, const parser::Module *, + const parser::Submodule *, const parser::SeparateModuleSubprogram *, + const parser::BlockData *> p; ParentType parent; }; diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index 246ba8fee946..82a84da1b3ac 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -21,7 +21,7 @@ namespace { /// the bridge to one such instantiation. class ASTBuilder { public: - ASTBuilder() : pgm{new AST::Program}, parents{pgm.get()} {} + ASTBuilder() : pgm{new AST::Program}, parents{*pgm.get()} {} /// Get the result std::unique_ptr result() { return std::move(pgm); } @@ -319,7 +319,7 @@ class ASTBuilder { auto &unit = addFunc(AST::FunctionLikeUnit{func, parents.back()}); funclist = &unit.funcs; pushEval(&unit.evals); - parents.emplace_back(&unit); + parents.emplace_back(unit); return true; } @@ -336,7 +336,7 @@ class ASTBuilder { auto &con = addEval(AST::Evaluation{construct, parents.back()}); con.subs.reset(new AST::EvaluationCollection); pushEval(con.subs.get()); - parents.emplace_back(&con); + parents.emplace_back(con); return true; } @@ -351,7 +351,7 @@ class ASTBuilder { bool enterModule(const A &func) { auto &unit = addUnit(AST::ModuleLikeUnit{func, parents.back()}); funclist = &unit.funcs; - parents.emplace_back(&unit); + parents.emplace_back(unit); return true; } @@ -728,7 +728,7 @@ void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, AST::FunctionLikeUnit::FunctionLikeUnit(const parser::MainProgram &func, const AST::ParentType &parent) - : ProgramUnit{&func, parent} { + : ProgramUnit{func, parent} { auto &ps{ std::get>>(func.t)}; if (ps.has_value()) { @@ -741,7 +741,7 @@ AST::FunctionLikeUnit::FunctionLikeUnit(const parser::MainProgram &func, AST::FunctionLikeUnit::FunctionLikeUnit(const parser::FunctionSubprogram &func, const AST::ParentType &parent) - : ProgramUnit{&func, parent} { + : ProgramUnit{func, parent} { funStmts.push_back( &std::get>(func.t)); funStmts.push_back( @@ -750,7 +750,7 @@ AST::FunctionLikeUnit::FunctionLikeUnit(const parser::FunctionSubprogram &func, AST::FunctionLikeUnit::FunctionLikeUnit( const parser::SubroutineSubprogram &func, const AST::ParentType &parent) - : ProgramUnit{&func, parent} { + : ProgramUnit{func, parent} { funStmts.push_back( &std::get>(func.t)); funStmts.push_back( @@ -759,7 +759,7 @@ AST::FunctionLikeUnit::FunctionLikeUnit( AST::FunctionLikeUnit::FunctionLikeUnit( const parser::SeparateModuleSubprogram &func, const AST::ParentType &parent) - : ProgramUnit{&func, parent} { + : ProgramUnit{func, parent} { funStmts.push_back( &std::get>(func.t)); funStmts.push_back( @@ -768,14 +768,14 @@ AST::FunctionLikeUnit::FunctionLikeUnit( AST::ModuleLikeUnit::ModuleLikeUnit(const parser::Module &m, const AST::ParentType &parent) - : ProgramUnit{&m, parent} { + : ProgramUnit{m, parent} { modStmts.push_back(&std::get>(m.t)); modStmts.push_back(&std::get>(m.t)); } AST::ModuleLikeUnit::ModuleLikeUnit(const parser::Submodule &m, const AST::ParentType &parent) - : ProgramUnit{&m, parent} { + : ProgramUnit{m, parent} { modStmts.push_back(&std::get>(m.t)); modStmts.push_back( &std::get>(m.t)); @@ -783,7 +783,7 @@ AST::ModuleLikeUnit::ModuleLikeUnit(const parser::Submodule &m, AST::BlockDataUnit::BlockDataUnit(const parser::BlockData &bd, const AST::ParentType &parent) - : ProgramUnit{&bd, parent} {} + : ProgramUnit{bd, parent} {} std::unique_ptr createAST(const parser::Program &root) { ASTBuilder walker; From 1bbdc328f730c106f725705c27eaa867fbea6413 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 4 Feb 2020 05:21:48 -0800 Subject: [PATCH 15/24] [review 959] Combine ASTBuilder Pre/Post visitor functions --- include/flang/lower/ASTBuilder.h | 14 +- lib/lower/ASTBuilder.cpp | 318 ++++++++----------------------- 2 files changed, 89 insertions(+), 243 deletions(-) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/ASTBuilder.h index e04122b87693..d89cf3682663 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/ASTBuilder.h @@ -110,19 +110,27 @@ using ConstructStmts = std::tuple< parser::MaskedElsewhereStmt, parser::ElsewhereStmt, parser::EndWhereStmt, parser::ForallConstructStmt, parser::EndForallStmt>; -/// is `A` a construct (or directive)? +template +constexpr static bool isActionStmt{common::HasMember}; + template constexpr static bool isConstruct{common::HasMember}; template -constexpr static bool isOtherStmt{common::HasMember}; +constexpr static bool isConstructStmts{common::HasMember}; template -constexpr static bool isActionStmt{common::HasMember}; +constexpr static bool isOtherStmt{common::HasMember}; template constexpr static bool isGenerated{std::is_same_v}; +template +constexpr static bool isFunctionLike{common::HasMember< + A, std::tuple>}; + /// Function-like units can contains lists of evaluations. These can be /// (simple) statements or constructs, where a construct contains its own /// evaluations. diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index 82a84da1b3ac..5542b37c8cc4 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -16,6 +16,52 @@ namespace Fortran::lower { namespace { +/// Helpers to unveil parser node inside parser::Statement<>, +/// parser::UnlabeledStatement, and common::Indirection<> +template +struct RemoveIndirectionHelper { + using Type = A; + static constexpr const Type &unwrap(const A &a) { return a; } +}; +template +struct RemoveIndirectionHelper> { + using Type = A; + static constexpr const Type &unwrap(const common::Indirection &a) { + return a.value(); + } +}; + +template +const auto &removeIndirection(const A &a) { + return RemoveIndirectionHelper::unwrap(a); +} + +template +struct UnwrapStmt { + static constexpr bool isStmt{false}; +}; +template +struct UnwrapStmt> { + static constexpr bool isStmt{true}; + using Type = typename RemoveIndirectionHelper::Type; + constexpr UnwrapStmt(const parser::Statement &a) + : unwrapped{removeIndirection(a.statement)}, pos{a.source}, lab{a.label} { + } + const Type &unwrapped; + parser::CharBlock pos; + std::optional lab; +}; +template +struct UnwrapStmt> { + static constexpr bool isStmt{true}; + using Type = typename RemoveIndirectionHelper::Type; + constexpr UnwrapStmt(const parser::UnlabeledStatement &a) + : unwrapped{removeIndirection(a.statement)}, pos{a.source} {} + const Type &unwrapped; + parser::CharBlock pos; + std::optional lab; +}; + /// The instantiation of a parse tree visitor (Pre and Post) is extremely /// expensive in terms of compile and link time, so one goal here is to limit /// the bridge to one such instantiation. @@ -27,157 +73,48 @@ class ASTBuilder { std::unique_ptr result() { return std::move(pgm); } template - constexpr bool Pre(const A &) { + constexpr bool Pre(const A &a) { + if constexpr (AST::isFunctionLike) { + return enterFunc(a); + } else if constexpr (AST::isConstruct) { + return enterConstruct(a); + } return true; } + template - constexpr void Post(const A &) {} + constexpr void Post(const A &a) { + if constexpr (AST::isFunctionLike) { + exitFunc(); + } else if constexpr (AST::isConstruct) { + exitConstruct(); + } else if constexpr (UnwrapStmt::isStmt) { + using T = typename UnwrapStmt::Type; + // Node "a" being visited has one of the following types: + // Statement, Statement, UnlabeledStatement, + // or UnlabeledStatement> + auto stmt{UnwrapStmt(a)}; + if constexpr (AST::isConstructStmts || AST::isOtherStmt) { + addEval(AST::Evaluation{stmt.unwrapped, parents.back(), stmt.pos, + stmt.lab}); + } else if constexpr (std::is_same_v) { + addEval(makeEvalAction(stmt.unwrapped, stmt.pos, stmt.lab)); + } + } + } // Module like - bool Pre(const parser::Module &node) { return enterModule(node); } bool Pre(const parser::Submodule &node) { return enterModule(node); } void Post(const parser::Module &) { exitModule(); } void Post(const parser::Submodule &) { exitModule(); } - // Function like - - bool Pre(const parser::MainProgram &node) { return enterFunc(node); } - bool Pre(const parser::FunctionSubprogram &node) { return enterFunc(node); } - bool Pre(const parser::SubroutineSubprogram &node) { return enterFunc(node); } - bool Pre(const parser::SeparateModuleSubprogram &node) { - return enterFunc(node); - } - - void Post(const parser::MainProgram &) { exitFunc(); } - void Post(const parser::FunctionSubprogram &) { exitFunc(); } - void Post(const parser::SubroutineSubprogram &) { exitFunc(); } - void Post(const parser::SeparateModuleSubprogram &) { exitFunc(); } - // Block data - void Post(const parser::BlockData &node) { addUnit(AST::BlockDataUnit{node, parents.back()}); } - // - // Action statements - // - - void Post(const parser::Statement &s) { - addEval(makeEvalAction(s)); - } - void Post(const parser::UnlabeledStatement &s) { - addEval(makeEvalAction(s)); - } - - // - // Non-executable statements - // - - void Post(const parser::Statement> - &statement) { - addEval(makeEvalIndirect(statement)); - } - void Post(const parser::Statement> - &statement) { - addEval(makeEvalIndirect(statement)); - } - void Post(const parser::Statement> - &statement) { - addEval(makeEvalIndirect(statement)); - } - void Post(const parser::Statement> - &statement) { - addEval(makeEvalIndirect(statement)); - } - - // - // Construct statements - // - - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } - void Post(const parser::Statement &statement) { - addEval(makeEvalDirect(statement)); - } // Get rid of production wrapper void Post(const parser::UnlabeledStatement &statement) { @@ -196,120 +133,21 @@ class ASTBuilder { statement.statement.u)); } - // - // Constructs (enter and exit) - // - - bool Pre(const parser::AssociateConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::BlockConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::CaseConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::ChangeTeamConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::CriticalConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::DoConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::IfConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::SelectRankConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::SelectTypeConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::WhereConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::ForallConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::CompilerDirective &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::OpenMPConstruct &construct) { - return enterConstruct(construct); - } - bool Pre(const parser::OmpEndLoopDirective &construct) { - return enterConstruct(construct); - } - - void Post(const parser::AssociateConstruct &) { exitConstruct(); } - void Post(const parser::BlockConstruct &) { exitConstruct(); } - void Post(const parser::CaseConstruct &) { exitConstruct(); } - void Post(const parser::ChangeTeamConstruct &) { exitConstruct(); } - void Post(const parser::CriticalConstruct &) { exitConstruct(); } - void Post(const parser::DoConstruct &) { exitConstruct(); } - void Post(const parser::IfConstruct &) { exitConstruct(); } - void Post(const parser::SelectRankConstruct &) { exitConstruct(); } - void Post(const parser::SelectTypeConstruct &) { exitConstruct(); } - void Post(const parser::WhereConstruct &) { exitConstruct(); } - void Post(const parser::ForallConstruct &) { exitConstruct(); } - void Post(const parser::CompilerDirective &) { exitConstruct(); } - void Post(const parser::OpenMPConstruct &) { exitConstruct(); } - void Post(const parser::OmpEndLoopDirective &) { exitConstruct(); } - private: // ActionStmt has a couple of non-conforming cases, which get handled // explicitly here. The other cases use an Indirection, which we discard in // the AST. - AST::Evaluation - makeEvalAction(const parser::Statement &statement) { + AST::Evaluation makeEvalAction(const parser::ActionStmt &statement, + parser::CharBlock pos, + std::optional lab) { return std::visit( common::visitors{ - [&](const parser::ContinueStmt &x) { - return AST::Evaluation{x, parents.back(), statement.source, - statement.label}; - }, - [&](const parser::FailImageStmt &x) { - return AST::Evaluation{x, parents.back(), statement.source, - statement.label}; - }, [&](const auto &x) { - return AST::Evaluation{x.value(), parents.back(), - statement.source, statement.label}; + return AST::Evaluation{removeIndirection(x), parents.back(), pos, + lab}; }, }, - statement.statement.u); - } - AST::Evaluation makeEvalAction( - const parser::UnlabeledStatement &statement) { - return std::visit( - common::visitors{ - [&](const parser::ContinueStmt &x) { - return AST::Evaluation{x, parents.back(), statement.source, {}}; - }, - [&](const parser::FailImageStmt &x) { - return AST::Evaluation{x, parents.back(), statement.source, {}}; - }, - [&](const auto &x) { - return AST::Evaluation{ - x.value(), parents.back(), statement.source, {}}; - }, - }, - statement.statement.u); - } - - template - AST::Evaluation - makeEvalIndirect(const parser::Statement> &statement) { - return AST::Evaluation{statement.statement.value(), parents.back(), - statement.source, statement.label}; - } - - template - AST::Evaluation makeEvalDirect(const parser::Statement &statement) { - return AST::Evaluation{statement.statement, parents.back(), - statement.source, statement.label}; + statement.u); } // When we enter a function-like structure, we want to build a new unit and From 6ade6153481cef0276ca9a090a33e4e91f226845 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 4 Feb 2020 10:38:05 -0800 Subject: [PATCH 16/24] [review 959] Combine visitor and functions where appropriate. --- lib/lower/ASTBuilder.cpp | 160 ++++++++++++++------------------------- 1 file changed, 56 insertions(+), 104 deletions(-) diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/ASTBuilder.cpp index 5542b37c8cc4..06c640818c3e 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/ASTBuilder.cpp @@ -246,63 +246,27 @@ class ASTBuilder { std::vector parents; }; -template -constexpr bool hasErrLabel(const A &stmt) { - auto isError{[](const auto &v) { - return std::holds_alternative(v.u); - }}; +template +constexpr bool hasLabel(const A &stmt) { + auto isLabel{ + [](const auto &v) { return std::holds_alternative, + "All ConstructStmts impact on the control flow " + "should be explicitly handled"); + } + /* else do nothing */ + }, }); } } From 2d87f1d71f6817ff9372871bf324a0af672b3a36 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 4 Feb 2020 10:39:58 -0800 Subject: [PATCH 17/24] [review 959] Reverts main .clang-format change After discussions, it turns out this change is not needed. --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 26741c32c6d4..21fb1ae51ac5 100644 --- a/.clang-format +++ b/.clang-format @@ -16,7 +16,7 @@ FixNamespaceComments: false IncludeCategories: - Regex: '^<' Priority: 4 - - Regex: '^"(llvm|llvm-c|clang|clang-c|fir|mlir|mlir-c)/' + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 3 - Regex: '^"(flang|\.\.)/' Priority: 2 From 2974de2aa444afc18891a6c210b5eafb24329dc9 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 4 Feb 2020 10:42:38 -0800 Subject: [PATCH 18/24] [review 959] Fix template step issue with clang: REMOVE AT REBASE This patch is a forward integration of an issue fix that will be fixed in parallel in f18, remove when rebasing whith next f18 containing the fix. --- include/flang/common/template.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/include/flang/common/template.h b/include/flang/common/template.h index c8a18e704fb4..460f1a8bdaed 100644 --- a/include/flang/common/template.h +++ b/include/flang/common/template.h @@ -153,15 +153,12 @@ template struct VariantToTupleHelper> { template using VariantToTuple = typename VariantToTupleHelper::type; -template -struct AreTypesDistinctHelper { +template struct AreTypesDistinctHelper { static constexpr bool value() { - if constexpr (std::is_same_v) { - return false; - } if constexpr (sizeof...(REST) > 0) { - return AreTypesDistinctHelper::value() && - AreTypesDistinctHelper::value(); + // extra () for clang-format + return ((... && !std::is_same_v)) && + AreTypesDistinctHelper::value(); } return true; } From 37861c00b4b7ecb9fba299ca6906c7fc32b30429 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Wed, 5 Feb 2020 06:50:33 -0800 Subject: [PATCH 19/24] [review 959] Rename AST to Pre-Fir Tree (PFT) --- .../lower/{ASTBuilder.h => PFTBuilder.h} | 50 ++--- lib/lower/CMakeLists.txt | 2 +- lib/lower/{ASTBuilder.cpp => PFTBuilder.cpp} | 184 +++++++++--------- 3 files changed, 119 insertions(+), 117 deletions(-) rename include/flang/lower/{ASTBuilder.h => PFTBuilder.h} (90%) rename lib/lower/{ASTBuilder.cpp => PFTBuilder.cpp} (78%) diff --git a/include/flang/lower/ASTBuilder.h b/include/flang/lower/PFTBuilder.h similarity index 90% rename from include/flang/lower/ASTBuilder.h rename to include/flang/lower/PFTBuilder.h index d89cf3682663..6e8e65b227ad 100644 --- a/include/flang/lower/ASTBuilder.h +++ b/include/flang/lower/PFTBuilder.h @@ -1,4 +1,4 @@ -//===-- include/flang/lower/ASTBuilder.h ------------------------*- C++ -*-===// +//===-- include/flang/lower/PFTBuilder.h ------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,26 +6,28 @@ // //===----------------------------------------------------------------------===// -#ifndef FORTRAN_LOWER_AST_BUILDER_H_ -#define FORTRAN_LOWER_AST_BUILDER_H_ +#ifndef FORTRAN_LOWER_PFT_BUILDER_H_ +#define FORTRAN_LOWER_PFT_BUILDER_H_ #include "flang/common/template.h" #include "flang/parser/parse-tree.h" #include "llvm/Support/raw_ostream.h" #include -/// Build a light-weight AST to help with lowering to FIR. The AST will -/// capture pointers back into the parse tree, so the parse tree data structure -/// may not be changed between the construction of the AST and all of -/// its uses. +/// Build a light-weight tree over the parse-tree to help with lowering to FIR. +/// It is named Pre-FIR Tree (PFT) to underline it has no other usage than +/// helping lowering to FIR. +/// The PFT will capture pointers back into the parse tree, so the parse tree +/// data structure may not be changed between the construction of the +/// PFT and all of its uses. /// -/// The AST captures a structured view of the program. The program is a list of +/// The PFT captures a structured view of the program. The program is a list of /// units. Function like units will contain lists of evaluations. Evaluations /// are either statements or constructs, where a construct contains a list of -/// evaluations. The resulting AST structure can then be used to create FIR. +/// evaluations. The resulting PFT structure can then be used to create FIR. namespace Fortran::lower { -namespace AST { +namespace PFT { struct Evaluation; struct Program; @@ -34,7 +36,7 @@ struct FunctionLikeUnit; // TODO: A collection of Evaluations can obviously be any of the container // types; leaving this as a std::list _for now_ because we reserve the right to -// insert AST nodes in any order in O(1) time. +// insert PFT nodes in any order in O(1) time. using EvaluationCollection = std::list; struct ParentType { @@ -64,7 +66,7 @@ enum class CFGAnnotation { /// Compiler-generated jump /// /// This is used to convert implicit control-flow edges to explicit form in the -/// decorated AST +/// decorated PFT struct CGJump { CGJump(Evaluation &to) : target{to} {} Evaluation ⌖ @@ -188,7 +190,7 @@ struct Evaluation { /// Construct ctor template Evaluation(const A &a, const ParentType &parent) : u{&a}, parent{parent} { - static_assert(AST::isConstruct, "must be a construct"); + static_assert(PFT::isConstruct, "must be a construct"); } constexpr bool isActionOrGenerated() const { @@ -216,10 +218,10 @@ struct Evaluation { setBranches(cstr); } - /// Is this evaluation a control-flow origin? (The AST must be annotated) + /// Is this evaluation a control-flow origin? (The PFT must be annotated) bool isControlOrigin() const { return cfg != CFGAnnotation::None; } - /// Is this evaluation a control-flow target? (The AST must be annotated) + /// Is this evaluation a control-flow target? (The PFT must be annotated) bool isControlTarget() const { return isTarget; } /// Set the containsBranches flag iff this evaluation (a construct) contains @@ -342,7 +344,7 @@ struct BlockDataUnit : public ProgramUnit { BlockDataUnit(const BlockDataUnit &) = delete; }; -/// A Program is the top-level AST +/// A Program is the top-level PFT struct Program { using Units = std::variant; @@ -356,19 +358,19 @@ struct Program { std::list units; }; -} // namespace AST +} // namespace PFT -/// Create an AST from the parse tree -std::unique_ptr createAST(const parser::Program &root); +/// Create an PFT from the parse tree +std::unique_ptr createPFT(const parser::Program &root); -/// Decorate the AST with control flow annotations +/// Decorate the PFT with control flow annotations /// -/// The AST must be decorated with control-flow annotations to prepare it for +/// The PFT must be decorated with control-flow annotations to prepare it for /// use in generating a CFG-like structure. -void annotateControl(AST::Program &ast); +void annotateControl(PFT::Program &); -void dumpAST(llvm::raw_ostream &o, AST::Program &ast); +void dumpPFT(llvm::raw_ostream &o, PFT::Program &); } // namespace Fortran::lower -#endif // FORTRAN_LOWER_AST_BUILDER_H_ +#endif // FORTRAN_LOWER_PFT_BUILDER_H_ diff --git a/lib/lower/CMakeLists.txt b/lib/lower/CMakeLists.txt index fa0b3b4d2ad0..25802de2a0d1 100644 --- a/lib/lower/CMakeLists.txt +++ b/lib/lower/CMakeLists.txt @@ -1,7 +1,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error") add_library(FortranLower - ASTBuilder.cpp + PFTBuilder.cpp ) target_link_libraries(FortranLower diff --git a/lib/lower/ASTBuilder.cpp b/lib/lower/PFTBuilder.cpp similarity index 78% rename from lib/lower/ASTBuilder.cpp rename to lib/lower/PFTBuilder.cpp index 06c640818c3e..c3d3d485ba33 100644 --- a/lib/lower/ASTBuilder.cpp +++ b/lib/lower/PFTBuilder.cpp @@ -1,4 +1,4 @@ -//===-- lib/lower/ASTBuilder.cc -------------------------------------------===// +//===-- lib/lower/PFTBuilder.cc -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "flang/lower/ASTBuilder.h" +#include "flang/lower/PFTBuilder.h" #include "flang/parser/dump-parse-tree.h" #include "flang/parser/parse-tree-visitor.h" #include @@ -65,18 +65,18 @@ struct UnwrapStmt> { /// The instantiation of a parse tree visitor (Pre and Post) is extremely /// expensive in terms of compile and link time, so one goal here is to limit /// the bridge to one such instantiation. -class ASTBuilder { +class PFTBuilder { public: - ASTBuilder() : pgm{new AST::Program}, parents{*pgm.get()} {} + PFTBuilder() : pgm{new PFT::Program}, parents{*pgm.get()} {} /// Get the result - std::unique_ptr result() { return std::move(pgm); } + std::unique_ptr result() { return std::move(pgm); } template constexpr bool Pre(const A &a) { - if constexpr (AST::isFunctionLike) { + if constexpr (PFT::isFunctionLike) { return enterFunc(a); - } else if constexpr (AST::isConstruct) { + } else if constexpr (PFT::isConstruct) { return enterConstruct(a); } return true; @@ -84,9 +84,9 @@ class ASTBuilder { template constexpr void Post(const A &a) { - if constexpr (AST::isFunctionLike) { + if constexpr (PFT::isFunctionLike) { exitFunc(); - } else if constexpr (AST::isConstruct) { + } else if constexpr (PFT::isConstruct) { exitConstruct(); } else if constexpr (UnwrapStmt::isStmt) { using T = typename UnwrapStmt::Type; @@ -94,8 +94,8 @@ class ASTBuilder { // Statement, Statement, UnlabeledStatement, // or UnlabeledStatement> auto stmt{UnwrapStmt(a)}; - if constexpr (AST::isConstructStmts || AST::isOtherStmt) { - addEval(AST::Evaluation{stmt.unwrapped, parents.back(), stmt.pos, + if constexpr (PFT::isConstructStmts || PFT::isOtherStmt) { + addEval(PFT::Evaluation{stmt.unwrapped, parents.back(), stmt.pos, stmt.lab}); } else if constexpr (std::is_same_v) { addEval(makeEvalAction(stmt.unwrapped, stmt.pos, stmt.lab)); @@ -112,7 +112,7 @@ class ASTBuilder { // Block data void Post(const parser::BlockData &node) { - addUnit(AST::BlockDataUnit{node, parents.back()}); + addUnit(PFT::BlockDataUnit{node, parents.back()}); } // Get rid of production wrapper @@ -120,14 +120,14 @@ class ASTBuilder { &statement) { addEval(std::visit( [&](const auto &x) { - return AST::Evaluation{x, parents.back(), statement.source, {}}; + return PFT::Evaluation{x, parents.back(), statement.source, {}}; }, statement.statement.u)); } void Post(const parser::Statement &statement) { addEval(std::visit( [&](const auto &x) { - return AST::Evaluation{x, parents.back(), statement.source, + return PFT::Evaluation{x, parents.back(), statement.source, statement.label}; }, statement.statement.u)); @@ -136,14 +136,14 @@ class ASTBuilder { private: // ActionStmt has a couple of non-conforming cases, which get handled // explicitly here. The other cases use an Indirection, which we discard in - // the AST. - AST::Evaluation makeEvalAction(const parser::ActionStmt &statement, + // the PFT. + PFT::Evaluation makeEvalAction(const parser::ActionStmt &statement, parser::CharBlock pos, std::optional lab) { return std::visit( common::visitors{ [&](const auto &x) { - return AST::Evaluation{removeIndirection(x), parents.back(), pos, + return PFT::Evaluation{removeIndirection(x), parents.back(), pos, lab}; }, }, @@ -154,7 +154,7 @@ class ASTBuilder { // set the builder's cursors to point to it. template bool enterFunc(const A &func) { - auto &unit = addFunc(AST::FunctionLikeUnit{func, parents.back()}); + auto &unit = addFunc(PFT::FunctionLikeUnit{func, parents.back()}); funclist = &unit.funcs; pushEval(&unit.evals); parents.emplace_back(unit); @@ -171,8 +171,8 @@ class ASTBuilder { // set the builder's evaluation cursor to point to it. template bool enterConstruct(const A &construct) { - auto &con = addEval(AST::Evaluation{construct, parents.back()}); - con.subs.reset(new AST::EvaluationCollection); + auto &con = addEval(PFT::Evaluation{construct, parents.back()}); + con.subs.reset(new PFT::EvaluationCollection); pushEval(con.subs.get()); parents.emplace_back(con); return true; @@ -187,7 +187,7 @@ class ASTBuilder { // set the builder's function cursor to point to it. template bool enterModule(const A &func) { - auto &unit = addUnit(AST::ModuleLikeUnit{func, parents.back()}); + auto &unit = addUnit(PFT::ModuleLikeUnit{func, parents.back()}); funclist = &unit.funcs; parents.emplace_back(unit); return true; @@ -214,7 +214,7 @@ class ASTBuilder { } /// move the Evaluation to the end of the current list - AST::Evaluation &addEval(AST::Evaluation &&eval) { + PFT::Evaluation &addEval(PFT::Evaluation &&eval) { assert(funclist && "not in a function"); assert(evallist.size() > 0); evallist.back()->emplace_back(std::move(eval)); @@ -222,7 +222,7 @@ class ASTBuilder { } /// push a new list on the stack of Evaluation lists - void pushEval(AST::EvaluationCollection *eval) { + void pushEval(PFT::EvaluationCollection *eval) { assert(funclist && "not in a function"); assert(eval && eval->empty() && "evaluation list isn't correct"); evallist.emplace_back(eval); @@ -234,16 +234,16 @@ class ASTBuilder { evallist.pop_back(); } - std::unique_ptr pgm; + std::unique_ptr pgm; /// funclist points to FunctionLikeUnit::funcs list (resp. /// ModuleLikeUnit::funcs) when building a FunctionLikeUnit (resp. /// ModuleLikeUnit) to store internal procedures (resp. module procedures). /// Otherwise (e.g. when building the top level Program), it is null. - std::list *funclist{nullptr}; + std::list *funclist{nullptr}; /// evallist is a stack of pointer to FunctionLikeUnit::evals (or /// Evaluation::subs) that are being build. - std::vector evallist; - std::vector parents; + std::vector evallist; + std::vector parents; }; template @@ -287,16 +287,16 @@ bool hasAltReturns(const parser::CallStmt &callStmt) { /// /// \param cstr points to the current construct. It may be null at the top-level /// of a FunctionLikeUnit. -void altRet(AST::Evaluation &evaluation, const parser::CallStmt &callStmt, - AST::Evaluation *cstr) { +void altRet(PFT::Evaluation &evaluation, const parser::CallStmt &callStmt, + PFT::Evaluation *cstr) { if (hasAltReturns(callStmt)) - evaluation.setCFG(AST::CFGAnnotation::Switch, cstr); + evaluation.setCFG(PFT::CFGAnnotation::Switch, cstr); } /// \param cstr points to the current construct. It may be null at the top-level /// of a FunctionLikeUnit. -void annotateEvalListCFG(AST::EvaluationCollection &evaluationCollection, - AST::Evaluation *cstr) { +void annotateEvalListCFG(PFT::EvaluationCollection &evaluationCollection, + PFT::Evaluation *cstr) { bool nextIsTarget = false; for (auto &eval : evaluationCollection) { eval.isTarget = nextIsTarget; @@ -314,84 +314,84 @@ void annotateEvalListCFG(AST::EvaluationCollection &evaluationCollection, altRet(eval, statement, cstr); }, [&](const parser::CycleStmt &) { - eval.setCFG(AST::CFGAnnotation::Goto, cstr); + eval.setCFG(PFT::CFGAnnotation::Goto, cstr); }, [&](const parser::ExitStmt &) { - eval.setCFG(AST::CFGAnnotation::Goto, cstr); + eval.setCFG(PFT::CFGAnnotation::Goto, cstr); }, [&](const parser::FailImageStmt &) { - eval.setCFG(AST::CFGAnnotation::Terminate, cstr); + eval.setCFG(PFT::CFGAnnotation::Terminate, cstr); }, [&](const parser::GotoStmt &) { - eval.setCFG(AST::CFGAnnotation::Goto, cstr); + eval.setCFG(PFT::CFGAnnotation::Goto, cstr); }, [&](const parser::IfStmt &) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + eval.setCFG(PFT::CFGAnnotation::CondGoto, cstr); }, [&](const parser::ReturnStmt &) { - eval.setCFG(AST::CFGAnnotation::Return, cstr); + eval.setCFG(PFT::CFGAnnotation::Return, cstr); }, [&](const parser::StopStmt &) { - eval.setCFG(AST::CFGAnnotation::Terminate, cstr); + eval.setCFG(PFT::CFGAnnotation::Terminate, cstr); }, [&](const parser::ArithmeticIfStmt &) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); + eval.setCFG(PFT::CFGAnnotation::Switch, cstr); }, [&](const parser::AssignedGotoStmt &) { - eval.setCFG(AST::CFGAnnotation::IndGoto, cstr); + eval.setCFG(PFT::CFGAnnotation::IndGoto, cstr); }, [&](const parser::ComputedGotoStmt &) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); + eval.setCFG(PFT::CFGAnnotation::Switch, cstr); }, [&](const parser::WhereStmt &) { // fir.loop + fir.where around the next stmt eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + eval.setCFG(PFT::CFGAnnotation::Iterative, cstr); }, [&](const parser::ForallStmt &) { // fir.loop around the next stmt eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + eval.setCFG(PFT::CFGAnnotation::Iterative, cstr); }, - [&](AST::CGJump &) { eval.setCFG(AST::CFGAnnotation::Goto, cstr); }, + [&](PFT::CGJump &) { eval.setCFG(PFT::CFGAnnotation::Goto, cstr); }, [&](const parser::SelectCaseStmt &) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); + eval.setCFG(PFT::CFGAnnotation::Switch, cstr); }, [&](const parser::NonLabelDoStmt &) { eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + eval.setCFG(PFT::CFGAnnotation::Iterative, cstr); }, [&](const parser::EndDoStmt &) { eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Goto, cstr); + eval.setCFG(PFT::CFGAnnotation::Goto, cstr); }, [&](const parser::IfThenStmt &) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + eval.setCFG(PFT::CFGAnnotation::CondGoto, cstr); }, [&](const parser::ElseIfStmt &) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + eval.setCFG(PFT::CFGAnnotation::CondGoto, cstr); }, [&](const parser::SelectRankStmt &) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); + eval.setCFG(PFT::CFGAnnotation::Switch, cstr); }, [&](const parser::SelectTypeStmt &) { - eval.setCFG(AST::CFGAnnotation::Switch, cstr); + eval.setCFG(PFT::CFGAnnotation::Switch, cstr); }, [&](const parser::WhereConstruct &) { // mark the WHERE as if it were a DO loop eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + eval.setCFG(PFT::CFGAnnotation::Iterative, cstr); }, [&](const parser::WhereConstructStmt &) { - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + eval.setCFG(PFT::CFGAnnotation::CondGoto, cstr); }, [&](const parser::MaskedElsewhereStmt &) { eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::CondGoto, cstr); + eval.setCFG(PFT::CFGAnnotation::CondGoto, cstr); }, [&](const parser::ForallConstructStmt &) { eval.isTarget = true; - eval.setCFG(AST::CFGAnnotation::Iterative, cstr); + eval.setCFG(PFT::CFGAnnotation::Iterative, cstr); }, [&](const auto &stmt) { @@ -420,13 +420,13 @@ void annotateEvalListCFG(AST::EvaluationCollection &evaluationCollection, if (hasLabel(stmt) || hasLabel(stmt) || hasLabel(stmt)) - eval.setCFG(AST::CFGAnnotation::IoSwitch, cstr); + eval.setCFG(PFT::CFGAnnotation::IoSwitch, cstr); } else if constexpr (common::HasMember) { eval.isTarget = true; } else if constexpr (common::HasMember) { // Explicitly do nothing for these construct statements } else { - static_assert(!AST::isConstructStmts, + static_assert(!PFT::isConstructStmts, "All ConstructStmts impact on the control flow " "should be explicitly handled"); } @@ -436,15 +436,15 @@ void annotateEvalListCFG(AST::EvaluationCollection &evaluationCollection, } } -/// Annotate the AST with CFG source decorations (see CFGAnnotation) and mark +/// Annotate the PFT with CFG source decorations (see CFGAnnotation) and mark /// potential branch targets -inline void annotateFuncCFG(AST::FunctionLikeUnit &functionLikeUnit) { +inline void annotateFuncCFG(PFT::FunctionLikeUnit &functionLikeUnit) { annotateEvalListCFG(functionLikeUnit.evals, nullptr); } -llvm::StringRef evalName(AST::Evaluation &eval) { +llvm::StringRef evalName(PFT::Evaluation &eval) { return eval.visit(common::visitors{ - [](const AST::CGJump) { return "CGJump"; }, + [](const PFT::CGJump) { return "CGJump"; }, [](const auto &parseTreeNode) { return parser::ParseTreeDumper::GetNodeName(parseTreeNode); }, @@ -452,11 +452,11 @@ llvm::StringRef evalName(AST::Evaluation &eval) { } void dumpEvalList(llvm::raw_ostream &outputStream, - AST::EvaluationCollection &evaluationCollection, + PFT::EvaluationCollection &evaluationCollection, int indent = 1) { static const std::string white{" ++"}; std::string indentString{white.substr(0, indent * 2)}; - for (AST::Evaluation &eval : evaluationCollection) { + for (PFT::Evaluation &eval : evaluationCollection) { llvm::StringRef name{evalName(eval)}; if (eval.isConstruct()) { outputStream << indentString << "<<" << name << ">>\n"; @@ -470,7 +470,7 @@ void dumpEvalList(llvm::raw_ostream &outputStream, } void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, - AST::FunctionLikeUnit &functionLikeUnit) { + PFT::FunctionLikeUnit &functionLikeUnit) { llvm::StringRef unitKind{}; std::string name{}; std::string header{}; @@ -516,8 +516,8 @@ void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, } // namespace -AST::FunctionLikeUnit::FunctionLikeUnit(const parser::MainProgram &func, - const AST::ParentType &parent) +PFT::FunctionLikeUnit::FunctionLikeUnit(const parser::MainProgram &func, + const PFT::ParentType &parent) : ProgramUnit{func, parent} { auto &ps{ std::get>>(func.t)}; @@ -529,8 +529,8 @@ AST::FunctionLikeUnit::FunctionLikeUnit(const parser::MainProgram &func, &std::get>(func.t)); } -AST::FunctionLikeUnit::FunctionLikeUnit(const parser::FunctionSubprogram &func, - const AST::ParentType &parent) +PFT::FunctionLikeUnit::FunctionLikeUnit(const parser::FunctionSubprogram &func, + const PFT::ParentType &parent) : ProgramUnit{func, parent} { funStmts.push_back( &std::get>(func.t)); @@ -538,8 +538,8 @@ AST::FunctionLikeUnit::FunctionLikeUnit(const parser::FunctionSubprogram &func, &std::get>(func.t)); } -AST::FunctionLikeUnit::FunctionLikeUnit( - const parser::SubroutineSubprogram &func, const AST::ParentType &parent) +PFT::FunctionLikeUnit::FunctionLikeUnit( + const parser::SubroutineSubprogram &func, const PFT::ParentType &parent) : ProgramUnit{func, parent} { funStmts.push_back( &std::get>(func.t)); @@ -547,8 +547,8 @@ AST::FunctionLikeUnit::FunctionLikeUnit( &std::get>(func.t)); } -AST::FunctionLikeUnit::FunctionLikeUnit( - const parser::SeparateModuleSubprogram &func, const AST::ParentType &parent) +PFT::FunctionLikeUnit::FunctionLikeUnit( + const parser::SeparateModuleSubprogram &func, const PFT::ParentType &parent) : ProgramUnit{func, parent} { funStmts.push_back( &std::get>(func.t)); @@ -556,42 +556,42 @@ AST::FunctionLikeUnit::FunctionLikeUnit( &std::get>(func.t)); } -AST::ModuleLikeUnit::ModuleLikeUnit(const parser::Module &m, - const AST::ParentType &parent) +PFT::ModuleLikeUnit::ModuleLikeUnit(const parser::Module &m, + const PFT::ParentType &parent) : ProgramUnit{m, parent} { modStmts.push_back(&std::get>(m.t)); modStmts.push_back(&std::get>(m.t)); } -AST::ModuleLikeUnit::ModuleLikeUnit(const parser::Submodule &m, - const AST::ParentType &parent) +PFT::ModuleLikeUnit::ModuleLikeUnit(const parser::Submodule &m, + const PFT::ParentType &parent) : ProgramUnit{m, parent} { modStmts.push_back(&std::get>(m.t)); modStmts.push_back( &std::get>(m.t)); } -AST::BlockDataUnit::BlockDataUnit(const parser::BlockData &bd, - const AST::ParentType &parent) +PFT::BlockDataUnit::BlockDataUnit(const parser::BlockData &bd, + const PFT::ParentType &parent) : ProgramUnit{bd, parent} {} -std::unique_ptr createAST(const parser::Program &root) { - ASTBuilder walker; +std::unique_ptr createPFT(const parser::Program &root) { + PFTBuilder walker; Walk(root, walker); return walker.result(); } -void annotateControl(AST::Program &ast) { - for (auto &unit : ast.getUnits()) { +void annotateControl(PFT::Program &pft) { + for (auto &unit : pft.getUnits()) { std::visit(common::visitors{ - [](AST::BlockDataUnit &) {}, - [](AST::FunctionLikeUnit &func) { + [](PFT::BlockDataUnit &) {}, + [](PFT::FunctionLikeUnit &func) { annotateFuncCFG(func); for (auto &statement : func.funcs) { annotateFuncCFG(statement); } }, - [](AST::ModuleLikeUnit &unit) { + [](PFT::ModuleLikeUnit &unit) { for (auto &func : unit.funcs) { annotateFuncCFG(func); } @@ -601,20 +601,20 @@ void annotateControl(AST::Program &ast) { } } -/// Dump an AST. -void dumpAST(llvm::raw_ostream &outputStream, AST::Program &ast) { - for (auto &unit : ast.getUnits()) { +/// Dump an PFT. +void dumpPFT(llvm::raw_ostream &outputStream, PFT::Program &pft) { + for (auto &unit : pft.getUnits()) { std::visit(common::visitors{ - [&](AST::BlockDataUnit &) { + [&](PFT::BlockDataUnit &) { outputStream << "BlockData\nEndBlockData\n\n"; }, - [&](AST::FunctionLikeUnit &func) { + [&](PFT::FunctionLikeUnit &func) { dumpFunctionLikeUnit(outputStream, func); for (auto &func : func.funcs) { dumpFunctionLikeUnit(outputStream, func); } }, - [&](AST::ModuleLikeUnit &unit) { + [&](PFT::ModuleLikeUnit &unit) { for (auto &func : unit.funcs) { dumpFunctionLikeUnit(outputStream, func); } From 5335107c5f2c0cddc1532e81ea556653cf9b2a59 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 30 Jan 2020 08:38:55 -0800 Subject: [PATCH 20/24] [review 959] Add option to dump the Pre-FIR Tree in f18 driver --- tools/f18/CMakeLists.txt | 2 ++ tools/f18/f18.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/tools/f18/CMakeLists.txt b/tools/f18/CMakeLists.txt index 676549c95cf4..79f5c52d6a6c 100644 --- a/tools/f18/CMakeLists.txt +++ b/tools/f18/CMakeLists.txt @@ -18,6 +18,8 @@ target_link_libraries(f18 FortranParser FortranEvaluate FortranSemantics + LLVMSupport + FortranLower ) add_executable(f18-parse-demo diff --git a/tools/f18/f18.cpp b/tools/f18/f18.cpp index 56f008ba6fe1..f2a084204ee8 100644 --- a/tools/f18/f18.cpp +++ b/tools/f18/f18.cpp @@ -11,6 +11,7 @@ #include "flang/common/Fortran-features.h" #include "flang/common/default-kinds.h" #include "flang/evaluate/expression.h" +#include "flang/lower/PFTBuilder.h" #include "flang/parser/characters.h" #include "flang/parser/dump-parse-tree.h" #include "flang/parser/message.h" @@ -22,6 +23,7 @@ #include "flang/semantics/expression.h" #include "flang/semantics/semantics.h" #include "flang/semantics/unparse-with-symbols.h" +#include "llvm/Support/raw_ostream.h" #include #include #include @@ -92,6 +94,7 @@ struct DriverOptions { bool dumpUnparse{false}; bool dumpUnparseWithSymbols{false}; bool dumpParseTree{false}; + bool dumpPreFirTree{false}; bool dumpSymbols{false}; bool debugResolveNames{false}; bool debugNoSemantics{false}; @@ -308,6 +311,15 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options, nullptr /* action before each statement */, &asFortran); return {}; } + if (driver.dumpPreFirTree) { + if (auto ast{Fortran::lower::createPFT(parseTree)}) { + Fortran::lower::annotateControl(*ast); + Fortran::lower::dumpPFT(llvm::outs(), *ast); + } else { + std::cerr << "Pre FIR Tree is NULL.\n"; + exitStatus = EXIT_FAILURE; + } + } if (driver.parseOnly) { return {}; } @@ -475,6 +487,9 @@ int main(int argc, char *const argv[]) { options.needProvenanceRangeToCharBlockMappings = true; } else if (arg == "-fdebug-dump-parse-tree") { driver.dumpParseTree = true; + } else if (arg == "-fdebug-pre-fir-tree") { + driver.dumpPreFirTree = true; + } else if (arg == "-fdebug-resolve-names") { } else if (arg == "-fdebug-dump-symbols") { driver.dumpSymbols = true; } else if (arg == "-fdebug-resolve-names") { From 87bdb7818c434b7a415820b8ff1402451a8e4c88 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Mon, 10 Feb 2020 09:36:23 -0800 Subject: [PATCH 21/24] [rewview 959] Add pft lit tests and fix issues - Add lit test to test: 1. that the PFT tree structure is as expected 2. that the PFT captures all intented nodes - Fix: FunctionLike units were added in wrong lists after a module subprogram or an internal suprogram was visited by ASTBuilder. --- include/flang/lower/PFTBuilder.h | 20 ++- lib/lower/PFTBuilder.cpp | 79 ++++++--- test-lit/lower/pre-fir-tree01.f90 | 113 +++++++++++++ test-lit/lower/pre-fir-tree02.f90 | 262 ++++++++++++++++++++++++++++++ 4 files changed, 451 insertions(+), 23 deletions(-) create mode 100644 test-lit/lower/pre-fir-tree01.f90 create mode 100644 test-lit/lower/pre-fir-tree02.f90 diff --git a/include/flang/lower/PFTBuilder.h b/include/flang/lower/PFTBuilder.h index 6e8e65b227ad..fc1c3e8b22bc 100644 --- a/include/flang/lower/PFTBuilder.h +++ b/include/flang/lower/PFTBuilder.h @@ -119,7 +119,7 @@ template constexpr static bool isConstruct{common::HasMember}; template -constexpr static bool isConstructStmts{common::HasMember}; +constexpr static bool isConstructStmt{common::HasMember}; template constexpr static bool isOtherStmt{common::HasMember}; @@ -206,7 +206,11 @@ struct Evaluation { return visit(common::visitors{ [](auto &r) { using T = std::decay_t; - return isActionStmt || isOtherStmt; + static constexpr bool isStmt{isActionStmt || isOtherStmt || + isConstructStmt}; + static_assert(!(isStmt && PFT::isConstruct), + "statement classification is inconsistent"); + return isStmt; }, }); } @@ -228,8 +232,16 @@ struct Evaluation { /// control flow void setBranches() { containsBranches = true; } - constexpr EvaluationCollection *getConstructEvals() { - return isStmt() ? nullptr : subs.get(); + EvaluationCollection *getConstructEvals() { + auto *evals{subs.get()}; + if (isStmt() && !evals) { + return nullptr; + } + if (isConstruct() && evals) { + return evals; + } + llvm_unreachable("evaluation subs is inconsistent"); + return nullptr; } /// Set that the construct `cstr` (if not a nullptr) has branches. diff --git a/lib/lower/PFTBuilder.cpp b/lib/lower/PFTBuilder.cpp index c3d3d485ba33..04662a4edb84 100644 --- a/lib/lower/PFTBuilder.cpp +++ b/lib/lower/PFTBuilder.cpp @@ -94,7 +94,7 @@ class PFTBuilder { // Statement, Statement, UnlabeledStatement, // or UnlabeledStatement> auto stmt{UnwrapStmt(a)}; - if constexpr (PFT::isConstructStmts || PFT::isOtherStmt) { + if constexpr (PFT::isConstructStmt || PFT::isOtherStmt) { addEval(PFT::Evaluation{stmt.unwrapped, parents.back(), stmt.pos, stmt.lab}); } else if constexpr (std::is_same_v) { @@ -160,11 +160,22 @@ class PFTBuilder { parents.emplace_back(unit); return true; } + /// Make funclist to point to current parent function list if it exists. + void resetFuncList() { + if (!parents.empty()) { + std::visit(common::visitors{ + [&](PFT::FunctionLikeUnit *p) { funclist = &p->funcs; }, + [&](PFT::ModuleLikeUnit *p) { funclist = &p->funcs; }, + [&](auto *) { funclist = nullptr; }, + }, + parents.back().p); + } + } void exitFunc() { popEval(); - funclist = nullptr; parents.pop_back(); + resetFuncList(); } // When we enter a construct structure, we want to build a new construct and @@ -194,8 +205,8 @@ class PFTBuilder { } void exitModule() { - funclist = nullptr; parents.pop_back(); + resetFuncList(); } template @@ -301,8 +312,8 @@ void annotateEvalListCFG(PFT::EvaluationCollection &evaluationCollection, for (auto &eval : evaluationCollection) { eval.isTarget = nextIsTarget; nextIsTarget = false; - if (eval.isConstruct()) { - annotateEvalListCFG(*eval.getConstructEvals(), &eval); + if (auto *subs{eval.getConstructEvals()}) { + annotateEvalListCFG(*subs, &eval); // assume that the entry and exit are both possible branch targets nextIsTarget = true; } @@ -426,7 +437,7 @@ void annotateEvalListCFG(PFT::EvaluationCollection &evaluationCollection, } else if constexpr (common::HasMember) { // Explicitly do nothing for these construct statements } else { - static_assert(!PFT::isConstructStmts, + static_assert(!PFT::isConstructStmt, "All ConstructStmts impact on the control flow " "should be explicitly handled"); } @@ -451,6 +462,16 @@ llvm::StringRef evalName(PFT::Evaluation &eval) { }); } +template +void dumpParentInfo(llvm::raw_ostream &stream, const A &evalOrUnit) { + stream << " node:" << (const void *)&evalOrUnit << " parent:"; + std::visit( + common::visitors{ + [&stream](const auto *parent) { stream << (const void *)parent; }, + }, + evalOrUnit.parent.p); +} + void dumpEvalList(llvm::raw_ostream &outputStream, PFT::EvaluationCollection &evaluationCollection, int indent = 1) { @@ -458,13 +479,16 @@ void dumpEvalList(llvm::raw_ostream &outputStream, std::string indentString{white.substr(0, indent * 2)}; for (PFT::Evaluation &eval : evaluationCollection) { llvm::StringRef name{evalName(eval)}; - if (eval.isConstruct()) { - outputStream << indentString << "<<" << name << ">>\n"; - dumpEvalList(outputStream, *eval.getConstructEvals(), indent + 1); + if (auto *subs{eval.getConstructEvals()}) { + outputStream << indentString << "<<" << name << ">>"; + dumpParentInfo(outputStream, eval); + outputStream << "\n"; + dumpEvalList(outputStream, *subs, indent + 1); outputStream << indentString << "<>\n"; } else { - outputStream << indentString << name << ": " << eval.pos.ToString() - << '\n'; + outputStream << indentString << name << ": " << eval.pos.ToString(); + dumpParentInfo(outputStream, eval); + outputStream << "\n"; } } } @@ -507,13 +531,32 @@ void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, }, functionLikeUnit.funStmts.front()); outputStream << unitKind << ' ' << name; + dumpParentInfo(outputStream, functionLikeUnit); if (header.size()) outputStream << ": " << header; outputStream << '\n'; dumpEvalList(outputStream, functionLikeUnit.evals); + if (!functionLikeUnit.funcs.empty()) { + outputStream << "\nContains\n"; + for (auto &func : functionLikeUnit.funcs) { + dumpFunctionLikeUnit(outputStream, func); + } + outputStream << "EndContains\n"; + } outputStream << "End" << unitKind << ' ' << name << "\n\n"; } +void dumpModuleLikeUnit(llvm::raw_ostream &outputStream, + PFT::ModuleLikeUnit &moduleLikeUnit) { + outputStream << "ModuleLike: "; + dumpParentInfo(outputStream, moduleLikeUnit); + outputStream << "\nContains\n"; + for (auto &func : moduleLikeUnit.funcs) { + dumpFunctionLikeUnit(outputStream, func); + } + outputStream << "EndContains\nEndModuleLike\n\n"; +} + } // namespace PFT::FunctionLikeUnit::FunctionLikeUnit(const parser::MainProgram &func, @@ -603,21 +646,19 @@ void annotateControl(PFT::Program &pft) { /// Dump an PFT. void dumpPFT(llvm::raw_ostream &outputStream, PFT::Program &pft) { + outputStream << "PFT root node:" << (void *)&pft << "\n"; for (auto &unit : pft.getUnits()) { std::visit(common::visitors{ - [&](PFT::BlockDataUnit &) { - outputStream << "BlockData\nEndBlockData\n\n"; + [&](PFT::BlockDataUnit &unit) { + outputStream << "BlockData: "; + dumpParentInfo(outputStream, unit); + outputStream << "\nEndBlockData\n\n"; }, [&](PFT::FunctionLikeUnit &func) { dumpFunctionLikeUnit(outputStream, func); - for (auto &func : func.funcs) { - dumpFunctionLikeUnit(outputStream, func); - } }, [&](PFT::ModuleLikeUnit &unit) { - for (auto &func : unit.funcs) { - dumpFunctionLikeUnit(outputStream, func); - } + dumpModuleLikeUnit(outputStream, unit); }, }, unit); diff --git a/test-lit/lower/pre-fir-tree01.f90 b/test-lit/lower/pre-fir-tree01.f90 new file mode 100644 index 000000000000..7969ec210756 --- /dev/null +++ b/test-lit/lower/pre-fir-tree01.f90 @@ -0,0 +1,113 @@ +! RUN: %f18 -fdebug-pre-fir-tree -fparse-only %s | FileCheck %s + +! Test structure of the Pre-FIR tree + +! CHECK: PFT root node:0x[[#%x, ROOT:]] +! CHECK: Subroutine foo{{.*}} node:0x[[#%x, FOO:]] parent:0x[[#ROOT]] +subroutine foo() + ! CHECK: <>{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#FOO]] + ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO1]] + do i=1,5 + ! CHECK: PrintStmt{{.*}} parent:0x[[#DO1]] + print *, "hey" + ! CHECK: <>{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#DO1]] + do j=1,5 + ! CHECK: PrintStmt{{.*}} parent:0x[[#DO2]] + print *, "hello", i, j + ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO2]] + end do + ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO1]] + end do +! CHECK: EndSubroutine +end subroutine + +! CHECK: BlockData{{.*}} parent:0x[[#ROOT]] +block data + integer, parameter :: n = 100 + integer, dimension(n) :: a, b, c + common /arrays/ a, b, c +end + +! CHECK: ModuleLike{{.*}} node:0x[[#%x, TEST_MOD:]] parent:0x[[#ROOT]] +module test_mod +interface + ! check specification parts are not part of the PFT. + ! CHECK-NOT: node + module subroutine dump() + end subroutine +end interface + integer :: xdim + real, allocatable :: pressure(:) +contains + ! CHECK: Subroutine foo{{.*}} node:0x[[#%x, M_FOO:]] parent:0x[[#TEST_MOD]] + subroutine foo() + contains + ! CHECK: Subroutine subfoo{{.*}} node:0x[[#%x, SUBFOO:]] parent:0x[[#M_FOO]] + subroutine subfoo() + end subroutine + ! CHECK: Function subfoo2{{.*}} node:0x[[#%x, SUBFOO2:]] parent:0x[[#M_FOO]] + function subfoo2() + end function + end subroutine + + ! CHECK: Function foo2{{.*}} node:0x[[#%x, M_FOO2:]] parent:0x[[#TEST_MOD]] + function foo2(i, j) + integer i, j, foo2 + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#M_FOO2]] + foo2 = i + j + contains + ! CHECK: Subroutine subfoo{{.*}} node:0x[[#%x, SUBFOO:]] parent:0x[[#M_FOO2]] + subroutine subfoo() + end subroutine + end function +end module + +! CHECK: ModuleLike{{.*}} node:0x[[#%x, SUB_MOD:]] parent:0x[[#ROOT]] +submodule (test_mod) test_mod_impl +contains + ! CHECK: Subroutine foo{{.*}} node:0x[[#%x, SUBM_FOO:]] parent:0x[[#SUB_MOD]] + subroutine foo() + contains + ! CHECK: Subroutine subfoo{{.*}} node:0x[[#%x, SUBFOO:]] parent:0x[[#SUBM_FOO]] + subroutine subfoo() + end subroutine + ! CHECK: Function subfoo2{{.*}} node:0x[[#%x, SUBFOO2:]] parent:0x[[#SUBM_FOO]] + function subfoo2() + end function + end subroutine + ! CHECK: MpSubprogram dump{{.*}} node:0x[[#%x, MP_DUMP:]] parent:0x[[#SUB_MOD]] + module procedure dump + ! CHECK: FormatStmt{{.*}} parent:0x[[#MP_DUMP]] +11 format (2E16.4, I6) + ! CHECK: <>{{.*}} node:0x[[#%x, IF1:]] parent:0x[[#MP_DUMP]] + ! CHECK: IfThenStmt{{.*}} parent:0x[[#IF1]] + if (xdim > 100) then + ! CHECK: PrintStmt{{.*}} parent:0x[[#IF1]] + print *, "test: ", xdim + ! CHECK: ElseStmt{{.*}} parent:0x[[#IF1]] + else + ! CHECK: WriteStmt{{.*}} parent:0x[[#IF1]] + write (*, 11) "test: ", xdim, pressure + ! CHECK: EndIfStmt{{.*}} parent:0x[[#IF1]] + end if + end procedure +end submodule + +! CHECK: BlockData{{.*}} parent:0x[[#ROOT]] +block data + integer i, j, k + common /indexes/ i, j, k +end + +! CHECK: Function bar{{.*}} node:0x[[#%x, BAR:]] parent:0x[[#ROOT]] +function bar() +end function + +! CHECK: Program {{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] + ! check specification parts are not part of the PFT. + ! CHECK-NOT: node + use test_mod + real, allocatable :: x(:) + ! CHECK: AllocateStmt{{.*}} parent:0x[[#PROG]] + allocate(x(foo2(10, 30))) +end diff --git a/test-lit/lower/pre-fir-tree02.f90 b/test-lit/lower/pre-fir-tree02.f90 new file mode 100644 index 000000000000..ce47e6b732b8 --- /dev/null +++ b/test-lit/lower/pre-fir-tree02.f90 @@ -0,0 +1,262 @@ +! RUN: %f18 -fdebug-pre-fir-tree -fparse-only %s | FileCheck %s + +! Test Pre-FIR Rree captures all the intended nodes from the parse-tree + +! CHECK: PFT root node:0x[[#%x, ROOT:]] +! CHECK: Program test_prog{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] +program test_prog + ! Check specification part is not part of the tree. + interface + subroutine incr(i) + integer, intent(inout) :: i + end subroutine + end interface + integer :: i, j, k + real, allocatable, target :: x(:) + real :: y(100) + ! CHECK-NOT: node + ! CHECK: <>{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#PROG]] + ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO1]] + do i=1,5 + ! CHECK: PrintStmt{{.*}} parent:0x[[#DO1]] + print *, "hey" + ! CHECK: <>{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#DO1]] + ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO2]] + do j=1,5 + ! CHECK: PrintStmt{{.*}} parent:0x[[#DO2]] + print *, "hello", i, j + ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO2]] + end do + ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO1]] + end do + + ! CHECK: <>{{.*}} node:0x[[#%x, ASSOC:]] parent:0x[[#PROG]] + ! CHECK: AssociateStmt{{.*}} parent:0x[[#ASSOC]] + associate (k => i + j) + ! CHECK: AllocateStmt{{.*}} parent:0x[[#ASSOC]] + allocate(x(k)) + ! CHECK: EndAssociateStmt{{.*}} parent:0x[[#ASSOC]] + end associate + + ! CHECK: <>{{.*}} node:0x[[#%x, BLOCK:]] parent:0x[[#PROG]] + ! CHECK: BlockStmt{{.*}} parent:0x[[#BLOCK]] + block + integer :: k, l + real, pointer :: p(:) + ! CHECK: PointerAssignmentStmt{{.*}} parent:0x[[#BLOCK]] + p => x + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#BLOCK]] + k = size(p) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#BLOCK]] + l = 1 + ! CHECK: <>{{.*}} node:0x[[#%x, SELECTCASE:]] parent:0x[[#BLOCK]] + ! CHECK: SelectCaseStmt{{.*}} parent:0x[[#SELECTCASE]] + select case (k) + ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + case (:0) + ! CHECK: NullifyStmt{{.*}} parent:0x[[#SELECTCASE]] + nullify(p) + ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + case (1) + ! CHECK: <>{{.*}} node:0x[[#%x, IFTHEN:]] parent:0x[[#SELECTCASE]] + ! CHECK: IfThenStmt{{.*}} parent:0x[[#IFTHEN]] + if (p(1)>0.) then + ! CHECK: PrintStmt{{.*}} parent:0x[[#IFTHEN]] + print *, "+" + ! CHECK: ElseIfStmt{{.*}} parent:0x[[#IFTHEN]] + else if (p(1)==0.) then + ! CHECK: PrintStmt{{.*}} parent:0x[[#IFTHEN]] + print *, "0." + ! CHECK: ElseStmt{{.*}} parent:0x[[#IFTHEN]] + else + ! CHECK: PrintStmt{{.*}} parent:0x[[#IFTHEN]] + print *, "-" + ! CHECK: EndIfStmt{{.*}} parent:0x[[#IFTHEN]] + end if + ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + case (2:10) + ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + case default + ! Note: label-do-loop are canonicalized into do constructs + ! CHECK: <>{{.*}} node:0x[[#%x, DO3:]] parent:0x[[#SELECTCASE]] + ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO3]] + do 22 while(l<=k) + ! CHECK: IfStmt{{.*}} parent:0x[[#DO3]] + if (p(l)<0.) p(l)=cos(p(l)) + ! CHECK: CallStmt{{.*}} parent:0x[[#DO3]] +22 call incr(l) + ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO3]] + ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + case (100:) + ! CHECK: EndSelectStmt{{.*}} parent:0x[[#SELECTCASE]] + end select + ! CHECK: EndBlockStmt{{.*}} parent:0x[[#BLOCK]] + end block + + ! CHECK-NOT: WhereConstruct + ! CHECK: WhereStmt{{.*}} parent:0x[[#PROG]] + where (x > 1.) x = x/2. + + ! CHECK: <>{{.*}} node:0x[[#%x, WHERE:]] parent:0x[[#PROG]] + ! CHECK: WhereConstructStmt{{.*}} parent:0x[[#WHERE]] + where (x == 0.) + ! FIXME: assignment not captured here ? + x = 0.01 + ! CHECK: MaskedElsewhereStmt{{.*}} parent:0x[[#WHERE]] + elsewhere (x < 0.5) + x = x*2. + ! CHECK: ElsewhereStmt{{.*}} parent:0x[[#WHERE]] + elsewhere + x = x + 1. + ! CHECK: EndWhereStmt{{.*}} parent:0x[[#WHERE]] + end where + + ! CHECK-NOT: ForAllConstruct + ! CHECK: ForallStmt{{.*}} parent:0x[[#PROG]] + forall (i = 1:5) x = y(i) + + ! CHECK: <>{{.*}} node:0x[[#%x, FORALL:]] parent:0x[[#PROG]] + ! CHECK: ForallConstructStmt{{.*}} parent:0x[[#FORALL]] + forall (i = 1:5) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#FORALL]] + x(i) = x(i) + y(10*i) + ! CHECK: EndForallStmt{{.*}} parent:0x[[#FORALL]] + end forall + + ! CHECK: DeallocateStmt{{.*}} parent:0x[[#PROG]] + deallocate(x) +end + +! CHECK: ModuleLike{{.*}} node:0x[[#%x, MOD:]] parent:0x[[#ROOT]] +module test + type :: a_type + integer :: x + end type + type, extends(a_type) :: b_type + integer :: y + end type +contains + ! CHECK: Function foo{{.*}} node:0x[[#%x, FOO:]] parent:0x[[#MOD]] + function foo(x) + real x(..) + integer :: foo + ! CHECK: <>{{.*}} node:0x[[#%x, SELECTRANK:]] parent:0x[[#FOO]] + ! CHECK: SelectRankStmt{{.*}} parent:0x[[#SELECTRANK]] + select rank(x) + ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + rank (0) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + foo = 0 + ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + rank (*) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + foo = -1 + ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + rank (1) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + foo = 1 + ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + rank default + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + foo = 2 + ! CHECK: EndSelectStmt{{.*}} parent:0x[[#SELECTRANK]] + end select + end function + + ! CHECK: Function bar{{.*}} node:0x[[#%x, BAR:]] parent:0x[[#MOD]] + function bar(x) + class(*) :: x + ! CHECK: <>{{.*}} node:0x[[#%x, SELECTTYPE:]] parent:0x[[#BAR]] + ! CHECK: SelectTypeStmt{{.*}} parent:0x[[#SELECTTYPE]] + select type(x) + ! CHECK: TypeGuardStmt{{.*}} parent:0x[[#SELECTTYPE]] + type is (integer) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTTYPE]] + bar = 0 + ! CHECK: TypeGuardStmt{{.*}} parent:0x[[#SELECTTYPE]] + class is (a_type) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTTYPE]] + bar = 1 + ! CHECK: ReturnStmt{{.*}} parent:0x[[#SELECTTYPE]] + return + ! CHECK: TypeGuardStmt{{.*}} parent:0x[[#SELECTTYPE]] + class default + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTTYPE]] + bar = -1 + ! CHECK: EndSelectStmt{{.*}} parent:0x[[#SELECTTYPE]] + end select + end function + + ! CHECK: Subroutine sub{{.*}} node:0x[[#%x, SUB:]] parent:0x[[#MOD]] + subroutine sub(a) + real(4):: a + ! CompilerDirective + ! CHECK: <>{{.*}} parent:0x[[#SUB]] + !DIR$ IGNORE_TKR a + end subroutine + + +end module + +! CHECK: Subroutine altreturn{{.*}} node:0x[[#%x, ALTSUB:]] parent:0x[[#ROOT]] +subroutine altreturn(i, j, *, *) + ! CHECK: <>{{.*}} node:0x[[#%x, IFTHEN:]] parent:0x[[#ALTSUB]] + if (i>j) then + ! CHECK: ReturnStmt{{.*}} parent:0x[[#IFTHEN]] + return 1 + else + ! CHECK: ReturnStmt{{.*}} parent:0x[[#IFTHEN]] + return 2 + end if +end subroutine + + +! Remaining TODO + +! CHECK: Subroutine iocheck{{.*}} node:0x[[#%x, IO:]] parent:0x[[#ROOT]] +subroutine iocheck() +! WILLCHECK: BackspaceStmt{{.*}} parent:0x[[#]] +! WILLCHECK: CloseStmt{{.*}} parent:0x[[#]] +! WILLCHECK: OpenStmt{{.*}} parent:0x[[#]] +! WILLCHECK: PauseStmt{{.*}} parent:0x[[#]] +! WILLCHECK: ReadStmt{{.*}} parent:0x[[#]] +! WILLCHECK: RewindStmt{{.*}} parent:0x[[#]] +! WILLCHECK: WriteStmt{{.*}} parent:0x[[#]] +! WILLCHECK: InquireStmt{{.*}} parent:0x[[#]] +! WILLCHECK: WaitStmt{{.*}} parent:0x[[#]] +! WILLCHECK: EndfileStmt{{.*}} parent:0x[[#]] +! WILLCHECK: FlushStmt{{.*}} parent:0x[[#]] +end subroutine + +! CHECK: Subroutine sub2{{.*}} node:0x[[#%x, SUB2:]] parent:0x[[#ROOT]] +subroutine sub2() +! WILLCHECK: ArithmeticIfStmt{{.*}} parent:0x[[#]] +! WILLCHECK: AssignedGotoStmt{{.*}} parent:0x[[#]] +! WILLCHECK: AssignStmt{{.*}} parent:0x[[#]] +! WILLCHECK: ComputedGotoStmt{{.*}} parent:0x[[#]] +! WILLCHECK: ContinueStmt{{.*}} parent:0x[[#]] +! WILLCHECK: CycleStmt{{.*}} parent:0x[[#]] +! WILLCHECK: ExitStmt{{.*}} parent:0x[[#]] +! WILLCHECK: GotoStmt{{.*}} parent:0x[[#]] +! WILLCHECK: StopStmt{{.*}} parent:0x[[#]] +end subroutine + +! TODO: check others + +! TODO: openmp related tests +! common::Indirection, +! common::Indirection> + +! TODO: coarray related test +! common::Indirection, +! common::Indirection, +! WILLCHECK: EventPostStmt{{.*}} parent:0x[[#]] +! WILLCHECK: EventWaitStmt{{.*}} parent:0x[[#]] +! WILLCHECK: FormTeamStmt{{.*}} parent:0x[[#]] +! WILLCHECK: FailImageStmt{{.*}} parent:0x[[#]] +! WILLCHECK: LockStmt{{.*}} parent:0x[[#]] +! WILLCHECK: SyncAllStmt{{.*}} parent:0x[[#]] +! WILLCHECK: SyncImagesStmt{{.*}} parent:0x[[#]] +! WILLCHECK: SyncMemoryStmt{{.*}} parent:0x[[#]] +! WILLCHECK: SyncTeamStmt{{.*}} parent:0x[[#]] +! WILLCHECK: UnlockStmt{{.*}} parent:0x[[#]] From 009bbdadb2fc719e6e635af7785e977cc5fd219c Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 11 Feb 2020 09:48:08 -0800 Subject: [PATCH 22/24] [review 959] Finsish writing PFT tests. Related fixes and lit config update --- lib/lower/PFTBuilder.cpp | 32 ++++---- test-lit/CMakeLists.txt | 2 + test-lit/lit.cfg.py | 5 +- test-lit/lit.site.cfg.py.in | 1 + test-lit/lower/pre-fir-tree02.f90 | 129 +++++++++++++++++++++--------- test-lit/lower/pre-fir-tree03.f90 | 56 +++++++++++++ test-lit/lower/pre-fir-tree04.f90 | 66 +++++++++++++++ 7 files changed, 232 insertions(+), 59 deletions(-) create mode 100644 test-lit/lower/pre-fir-tree03.f90 create mode 100644 test-lit/lower/pre-fir-tree04.f90 diff --git a/lib/lower/PFTBuilder.cpp b/lib/lower/PFTBuilder.cpp index 04662a4edb84..d98dfe5e9fd4 100644 --- a/lib/lower/PFTBuilder.cpp +++ b/lib/lower/PFTBuilder.cpp @@ -161,7 +161,7 @@ class PFTBuilder { return true; } /// Make funclist to point to current parent function list if it exists. - void resetFuncList() { + void setFunctListToParentFuncs() { if (!parents.empty()) { std::visit(common::visitors{ [&](PFT::FunctionLikeUnit *p) { funclist = &p->funcs; }, @@ -175,7 +175,7 @@ class PFTBuilder { void exitFunc() { popEval(); parents.pop_back(); - resetFuncList(); + setFunctListToParentFuncs(); } // When we enter a construct structure, we want to build a new construct and @@ -206,7 +206,7 @@ class PFTBuilder { void exitModule() { parents.pop_back(); - resetFuncList(); + setFunctListToParentFuncs(); } template @@ -451,6 +451,8 @@ void annotateEvalListCFG(PFT::EvaluationCollection &evaluationCollection, /// potential branch targets inline void annotateFuncCFG(PFT::FunctionLikeUnit &functionLikeUnit) { annotateEvalListCFG(functionLikeUnit.evals, nullptr); + for (auto &internalFunc : functionLikeUnit.funcs) + annotateFuncCFG(internalFunc); } llvm::StringRef evalName(PFT::Evaluation &eval) { @@ -464,10 +466,12 @@ llvm::StringRef evalName(PFT::Evaluation &eval) { template void dumpParentInfo(llvm::raw_ostream &stream, const A &evalOrUnit) { - stream << " node:" << (const void *)&evalOrUnit << " parent:"; + stream << " node:" << static_cast(&evalOrUnit) << " parent:"; std::visit( common::visitors{ - [&stream](const auto *parent) { stream << (const void *)parent; }, + [&stream](const auto *parent) { + stream << static_cast(parent); + }, }, evalOrUnit.parent.p); } @@ -538,9 +542,8 @@ void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, dumpEvalList(outputStream, functionLikeUnit.evals); if (!functionLikeUnit.funcs.empty()) { outputStream << "\nContains\n"; - for (auto &func : functionLikeUnit.funcs) { + for (auto &func : functionLikeUnit.funcs) dumpFunctionLikeUnit(outputStream, func); - } outputStream << "EndContains\n"; } outputStream << "End" << unitKind << ' ' << name << "\n\n"; @@ -551,9 +554,8 @@ void dumpModuleLikeUnit(llvm::raw_ostream &outputStream, outputStream << "ModuleLike: "; dumpParentInfo(outputStream, moduleLikeUnit); outputStream << "\nContains\n"; - for (auto &func : moduleLikeUnit.funcs) { + for (auto &func : moduleLikeUnit.funcs) dumpFunctionLikeUnit(outputStream, func); - } outputStream << "EndContains\nEndModuleLike\n\n"; } @@ -628,16 +630,10 @@ void annotateControl(PFT::Program &pft) { for (auto &unit : pft.getUnits()) { std::visit(common::visitors{ [](PFT::BlockDataUnit &) {}, - [](PFT::FunctionLikeUnit &func) { - annotateFuncCFG(func); - for (auto &statement : func.funcs) { - annotateFuncCFG(statement); - } - }, + [](PFT::FunctionLikeUnit &func) { annotateFuncCFG(func); }, [](PFT::ModuleLikeUnit &unit) { - for (auto &func : unit.funcs) { + for (auto &func : unit.funcs) annotateFuncCFG(func); - } }, }, unit); @@ -646,7 +642,7 @@ void annotateControl(PFT::Program &pft) { /// Dump an PFT. void dumpPFT(llvm::raw_ostream &outputStream, PFT::Program &pft) { - outputStream << "PFT root node:" << (void *)&pft << "\n"; + outputStream << "PFT root node:" << static_cast(&pft) << "\n"; for (auto &unit : pft.getUnits()) { std::visit(common::visitors{ [&](PFT::BlockDataUnit &unit) { diff --git a/test-lit/CMakeLists.txt b/test-lit/CMakeLists.txt index 0819e57b81f3..111814303b0b 100644 --- a/test-lit/CMakeLists.txt +++ b/test-lit/CMakeLists.txt @@ -1,6 +1,8 @@ # Test runner infrastructure for Flang. This configures the Flang test trees # for use by Lit, and delegates to LLVM's lit test handlers. +set(FLANG_INTRINSIC_MODULES_DIR ${FLANG_BINARY_DIR}/tools/f18/include) + configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py diff --git a/test-lit/lit.cfg.py b/test-lit/lit.cfg.py index c27e6a616b85..3ca3c8ad23f7 100644 --- a/test-lit/lit.cfg.py +++ b/test-lit/lit.cfg.py @@ -61,9 +61,12 @@ # to search to ensure that we get the tools just built and not some random # tools that might happen to be in the user's PATH. tool_dirs = [config.llvm_tools_dir, config.flang_tools_dir] +flang_includes = "-I" + config.flang_intrinsic_modules_dir tools = [ToolSubst('%flang', command=FindTool('flang'), unresolved='fatal'), - ToolSubst('%f18', command=FindTool('f18'), unresolved='fatal')] + ToolSubst('%f18', command=FindTool('f18'), unresolved='fatal'), + ToolSubst('%f18_with_includes', command=FindTool('f18'), + extra_args=[flang_includes], unresolved='fatal')] llvm_config.add_tool_substitutions(tools, tool_dirs) diff --git a/test-lit/lit.site.cfg.py.in b/test-lit/lit.site.cfg.py.in index ad31bf1594f9..d00f3856fb41 100644 --- a/test-lit/lit.site.cfg.py.in +++ b/test-lit/lit.site.cfg.py.in @@ -6,6 +6,7 @@ config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" config.flang_obj_root = "@FLANG_BINARY_DIR@" config.flang_src_dir = "@FLANG_SOURCE_DIR@" config.flang_tools_dir = "@FLANG_TOOLS_DIR@" +config.flang_intrinsic_modules_dir = "@FLANG_INTRINSIC_MODULES_DIR@" config.python_executable = "@PYTHON_EXECUTABLE@" # Support substitution of the tools_dir with user parameters. This is diff --git a/test-lit/lower/pre-fir-tree02.f90 b/test-lit/lower/pre-fir-tree02.f90 index ce47e6b732b8..d0def9f54f11 100644 --- a/test-lit/lower/pre-fir-tree02.f90 +++ b/test-lit/lower/pre-fir-tree02.f90 @@ -1,6 +1,6 @@ ! RUN: %f18 -fdebug-pre-fir-tree -fparse-only %s | FileCheck %s -! Test Pre-FIR Rree captures all the intended nodes from the parse-tree +! Test Pre-FIR Tree captures all the intended nodes from the parse-tree ! CHECK: PFT root node:0x[[#%x, ROOT:]] ! CHECK: Program test_prog{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] @@ -213,50 +213,99 @@ subroutine altreturn(i, j, *, *) ! Remaining TODO -! CHECK: Subroutine iocheck{{.*}} node:0x[[#%x, IO:]] parent:0x[[#ROOT]] -subroutine iocheck() -! WILLCHECK: BackspaceStmt{{.*}} parent:0x[[#]] -! WILLCHECK: CloseStmt{{.*}} parent:0x[[#]] -! WILLCHECK: OpenStmt{{.*}} parent:0x[[#]] -! WILLCHECK: PauseStmt{{.*}} parent:0x[[#]] -! WILLCHECK: ReadStmt{{.*}} parent:0x[[#]] -! WILLCHECK: RewindStmt{{.*}} parent:0x[[#]] -! WILLCHECK: WriteStmt{{.*}} parent:0x[[#]] -! WILLCHECK: InquireStmt{{.*}} parent:0x[[#]] -! WILLCHECK: WaitStmt{{.*}} parent:0x[[#]] -! WILLCHECK: EndfileStmt{{.*}} parent:0x[[#]] -! WILLCHECK: FlushStmt{{.*}} parent:0x[[#]] +! CHECK: Subroutine iostmts{{.*}} node:0x[[#%x, IO:]] parent:0x[[#ROOT]] +subroutine iostmts(filename, a, b, c) + character(*) :: filename + integer :: length + logical :: file_is_opened + real, a, b ,c + ! CHECK: InquireStmt{{.*}} parent:0x[[#]] + inquire(file=filename, opened=file_is_opened) + ! CHECK: <>{{.*}} node:0x[[#%x, IFTHEN:]] parent:0x[[#IO]] + if (file_is_opened) then + ! CHECK: OpenStmt{{.*}} parent:0x[[#IFTHEN]] + open(10, FILE=filename) + end if + ! CHECK: ReadStmt{{.*}} parent:0x[[#IO]] + read(10, *) length + ! CHECK: RewindStmt{{.*}} parent:0x[[#IO]] + rewind 10 + ! CHECK: NamelistStmt{{.*}} parent:0x[[#IO]] + namelist /nlist/ a, b, c + ! CHECK: WriteStmt{{.*}} parent:0x[[#IO]] + write(10, NML=nlist) + ! CHECK: BackspaceStmt{{.*}} parent:0x[[#IO]] + backspace(10) + ! CHECK: FormatStmt{{.*}} parent:0x[[#IO]] +1 format (1PE12.4) + ! CHECK: WriteStmt{{.*}} parent:0x[[#IO]] + write (10, 1) a + ! CHECK: EndfileStmt{{.*}} parent:0x[[#IO]] + endfile 10 + ! CHECK: FlushStmt{{.*}} parent:0x[[#IO]] + flush 10 + ! CHECK: WaitStmt{{.*}} parent:0x[[#IO]] + wait(10) + ! CHECK: CloseStmt{{.*}} parent:0x[[#IO]] + close(10) end subroutine + ! CHECK: Subroutine sub2{{.*}} node:0x[[#%x, SUB2:]] parent:0x[[#ROOT]] subroutine sub2() -! WILLCHECK: ArithmeticIfStmt{{.*}} parent:0x[[#]] -! WILLCHECK: AssignedGotoStmt{{.*}} parent:0x[[#]] -! WILLCHECK: AssignStmt{{.*}} parent:0x[[#]] -! WILLCHECK: ComputedGotoStmt{{.*}} parent:0x[[#]] -! WILLCHECK: ContinueStmt{{.*}} parent:0x[[#]] -! WILLCHECK: CycleStmt{{.*}} parent:0x[[#]] -! WILLCHECK: ExitStmt{{.*}} parent:0x[[#]] -! WILLCHECK: GotoStmt{{.*}} parent:0x[[#]] -! WILLCHECK: StopStmt{{.*}} parent:0x[[#]] + integer :: i, j, k, l + i = 0 +1 j = i + ! CHECK: ContinueStmt{{.*}} parent:0x[[#SUB2]] +2 continue + i = i+1 +3 j = j+1 +! CHECK: ArithmeticIfStmt{{.*}} parent:0x[[#SUB2]] + if (j-i) 3, 4, 5 + ! CHECK: GotoStmt{{.*}} parent:0x[[#SUB2]] +4 goto 6 + +! FIXME: is name resolution on assigned goto broken/todo ? +! WILLCHECK: AssignStmt{{.*}} parent:0x[[#SUB2]] +!55 assign 6 to label +! WILLCHECK: AssignedGotoStmt{{.*}} parent:0x[[#SUB2]] +!66 go to label (5, 6) + +! CHECK: ComputedGotoStmt{{.*}} parent:0x[[#SUB2]] + go to (5, 6), 1 + mod(i, 2) +5 j = j + 1 +6 i = i + j/2 + + ! CHECK: <>{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#SUB2]] + do1: do k=1,10 + ! CHECK: <>{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#DO1]] + do2: do l=5,20 + ! CHECK: CycleStmt{{.*}} parent:0x[[#DO2]] + cycle do1 + ! CHECK: ExitStmt{{.*}} parent:0x[[#DO2]] + exit do2 + end do do2 + end do do1 + + ! CHECK: PauseStmt{{.*}} parent:0x[[#SUB2]] + pause 7 + ! CHECK: StopStmt{{.*}} parent:0x[[#SUB2]] + stop end subroutine -! TODO: check others -! TODO: openmp related tests -! common::Indirection, -! common::Indirection> +! CHECK: Subroutine sub3{{.*}} node:0x[[#%x, SUB3:]] parent:0x[[#ROOT]] +subroutine sub3() + print *, "normal" + ! CHECK: EntryStmt{{.*}} parent:0x[[#SUB3]] + entry sub4entry() + print *, "test" +end subroutine -! TODO: coarray related test -! common::Indirection, -! common::Indirection, -! WILLCHECK: EventPostStmt{{.*}} parent:0x[[#]] -! WILLCHECK: EventWaitStmt{{.*}} parent:0x[[#]] -! WILLCHECK: FormTeamStmt{{.*}} parent:0x[[#]] -! WILLCHECK: FailImageStmt{{.*}} parent:0x[[#]] -! WILLCHECK: LockStmt{{.*}} parent:0x[[#]] -! WILLCHECK: SyncAllStmt{{.*}} parent:0x[[#]] -! WILLCHECK: SyncImagesStmt{{.*}} parent:0x[[#]] -! WILLCHECK: SyncMemoryStmt{{.*}} parent:0x[[#]] -! WILLCHECK: SyncTeamStmt{{.*}} parent:0x[[#]] -! WILLCHECK: UnlockStmt{{.*}} parent:0x[[#]] +! CHECK: Subroutine sub4{{.*}} node:0x[[#%x, SUB4:]] parent:0x[[#ROOT]] +subroutine sub4(i, j) + integer :: i + print*, "test" + ! CHECK: DataStmt{{.*}} parent:0x[[#SUB4]] + data i /1/ +end subroutine diff --git a/test-lit/lower/pre-fir-tree03.f90 b/test-lit/lower/pre-fir-tree03.f90 new file mode 100644 index 000000000000..acd73e2a534c --- /dev/null +++ b/test-lit/lower/pre-fir-tree03.f90 @@ -0,0 +1,56 @@ +! RUN: %f18 -fdebug-pre-fir-tree -fparse-only -fopenmp %s | FileCheck %s + +! Test Pre-FIR Tree captures OpenMP related constructs + +! CHECK: PFT root node:0x[[#%x, ROOT:]] +! CHECK: Program test_omp{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] +program test_omp + ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + print *, "sequential" + + ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_PAR:]] parent:0x[[#PROG]] + !$omp parallel + + ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_PAR]] + print *, "in omp //" + ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_LOOP:]] parent:0x[[#OMP_PAR]] + !$omp do + ! CHECK: DoConstruct{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#OMP_LOOP]] + ! CHECK: LabelDoStmt{{.*}} parent:0x[[#DO1]] + do i=1,100 + ! CHECK: PrintStmt{{.*}} parent:0x[[#DO1]] + print *, "in omp do" + ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO1]] + end do + ! CHECK: OmpEndLoopDirective{{.*}} parent:0x[[#OMP_LOOP]] + !$omp end do + + ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_PAR]] + print *, "not in omp do" + + ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_LOOP2:]] parent:0x[[#OMP_PAR]] + !$omp do + ! CHECK: DoConstruct{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#OMP_LOOP2]] + ! CHECK: LabelDoStmt{{.*}} parent:0x[[#DO2]] + do i=1,100 + ! CHECK: PrintStmt{{.*}} parent:0x[[#DO2]] + print *, "in omp do" + ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO2]] + end do + ! CHECK-NOT: OmpEndLoopDirective + ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_PAR]] + print *, "no in omp do" + !$omp end parallel + + ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + print *, "sequential again" + + ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_TASK:]] parent:0x[[#PROG]] + !$omp task + ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_TASK]] + print *, "in task" + !$omp end task + + ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + print *, "sequential again" +end program diff --git a/test-lit/lower/pre-fir-tree04.f90 b/test-lit/lower/pre-fir-tree04.f90 new file mode 100644 index 000000000000..a64e1422ca4d --- /dev/null +++ b/test-lit/lower/pre-fir-tree04.f90 @@ -0,0 +1,66 @@ +! RUN: %f18_with_includes -fdebug-pre-fir-tree -fparse-only %s | FileCheck %s + +! Test Pre-FIR Tree captures all the coarray related statements + +! CHECK: PFT root node:0x[[#%x, ROOT:]] +! CHECK: Subroutine test_coarray{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] +Subroutine test_coarray + use iso_fortran_env, only: team_type, event_type, lock_type + type(team_type) :: t + type(event_type) :: done + type(lock_type) :: alock + real :: y[10,*] + integer :: counter[*] + logical :: is_master + ! CHECK: ChangeTeamConstruct{{.*}} node:0x[[#%x, CHANGE_TEAM:]] parent:0x[[#PROG]] + change team(t, x[5,*] => y) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#CHANGE_TEAM]] + x = x[4, 1] + end team + ! CHECK: FormTeamStmt{{.*}} parent:0x[[#PROG]] + form team(1, t) + + ! CHECK: IfConstruct{{.*}} node:0x[[#%x, IF:]] parent:0x[[#PROG]] + if (this_image() == 1) then + ! CHECK: EventPostStmt{{.*}} parent:0x[[#IF]] + event post (done) + else + ! CHECK: EventWaitStmt{{.*}} parent:0x[[#IF]] + event wait (done) + end if + + ! CHECK: CriticalConstruct{{.*}} node:0x[[#%x, CRITICAL:]] parent:0x[[#PROG]] + critical + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#CRITICAL]] + counter[1] = counter[1] + 1 + end critical + + ! CHECK: LockStmt{{.*}} parent:0x[[#PROG]] + lock(alock) + ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + print *, "I have the lock" + ! CHECK: UnlockStmt{{.*}} parent:0x[[#PROG]] + unlock(alock) + + ! CHECK: SyncAllStmt{{.*}} parent:0x[[#PROG]] + sync all + ! CHECK: SyncMemoryStmt{{.*}} parent:0x[[#PROG]] + sync memory + ! CHECK: SyncTeamStmt{{.*}} parent:0x[[#PROG]] + sync team(t) + + ! CHECK: IfConstruct{{.*}} node:0x[[#%x, IF2:]] parent:0x[[#PROG]] + if (this_image() == 1) then + ! CHECK: SyncImagesStmt{{.*}} parent:0x[[#IF2]] + sync images(*) + else + ! CHECK: SyncImagesStmt{{.*}} parent:0x[[#IF2]] + sync images(1) + end if + + ! CHECK: IfConstruct{{.*}} node:0x[[#%x, IF3:]] parent:0x[[#PROG]] + if (y<0.) then + ! CHECK: FailImageStmt{{.*}} parent:0x[[#IF3]] + fail image + end if +end From 625e23a395cff5f83565076eb8d99a86e800214b Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 11 Feb 2020 10:34:20 -0800 Subject: [PATCH 23/24] [review 959] Fix capture of WhereBodyConstruct AssignementStmt in PFT --- lib/lower/PFTBuilder.cpp | 12 ++++++++++++ test-lit/lower/pre-fir-tree02.f90 | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/lower/PFTBuilder.cpp b/lib/lower/PFTBuilder.cpp index d98dfe5e9fd4..634f4b0cdc4d 100644 --- a/lib/lower/PFTBuilder.cpp +++ b/lib/lower/PFTBuilder.cpp @@ -132,6 +132,18 @@ class PFTBuilder { }, statement.statement.u)); } + void Post(const parser::WhereBodyConstruct &whereBody) { + std::visit(common::visitors{ + [&](const parser::Statement &stmt) { + // Not caught as other AssignmentStmt because it is not + // wrapped in a parser::ActionStmt. + addEval(PFT::Evaluation{stmt.statement, parents.back(), + stmt.source, stmt.label}); + }, + [&](const auto &) { /* Already handled*/ }, + }, + whereBody.u); + } private: // ActionStmt has a couple of non-conforming cases, which get handled diff --git a/test-lit/lower/pre-fir-tree02.f90 b/test-lit/lower/pre-fir-tree02.f90 index d0def9f54f11..c2c792b2b25d 100644 --- a/test-lit/lower/pre-fir-tree02.f90 +++ b/test-lit/lower/pre-fir-tree02.f90 @@ -1,6 +1,7 @@ ! RUN: %f18 -fdebug-pre-fir-tree -fparse-only %s | FileCheck %s ! Test Pre-FIR Tree captures all the intended nodes from the parse-tree +! Coarray and OpenMP related nodes are tested in other files. ! CHECK: PFT root node:0x[[#%x, ROOT:]] ! CHECK: Program test_prog{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] @@ -100,13 +101,20 @@ subroutine incr(i) ! CHECK: <>{{.*}} node:0x[[#%x, WHERE:]] parent:0x[[#PROG]] ! CHECK: WhereConstructStmt{{.*}} parent:0x[[#WHERE]] where (x == 0.) - ! FIXME: assignment not captured here ? + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE]] x = 0.01 ! CHECK: MaskedElsewhereStmt{{.*}} parent:0x[[#WHERE]] elsewhere (x < 0.5) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE]] x = x*2. + ! CHECK: <>{{.*}} node:0x[[#%x, WHERE2:]] parent:0x[[#WHERE]] + where (y > 0.4) + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE2]] + y = y/2. + end where ! CHECK: ElsewhereStmt{{.*}} parent:0x[[#WHERE]] elsewhere + ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE]] x = x + 1. ! CHECK: EndWhereStmt{{.*}} parent:0x[[#WHERE]] end where From 77c0a3b411d8c710b38ba6a77a30a430f42e4f47 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Wed, 12 Feb 2020 07:43:49 -0800 Subject: [PATCH 24/24] [review 959] Keep PFT dump human readable and update tests. Fix PFT builder for IfStmt. --- lib/lower/PFTBuilder.cpp | 310 +++++++++++++++++------------- test-lit/lower/pre-fir-tree01.f90 | 66 +++---- test-lit/lower/pre-fir-tree02.f90 | 242 +++++++++++------------ test-lit/lower/pre-fir-tree03.f90 | 44 ++--- test-lit/lower/pre-fir-tree04.f90 | 42 ++-- 5 files changed, 372 insertions(+), 332 deletions(-) diff --git a/lib/lower/PFTBuilder.cpp b/lib/lower/PFTBuilder.cpp index 634f4b0cdc4d..95a7860b7321 100644 --- a/lib/lower/PFTBuilder.cpp +++ b/lib/lower/PFTBuilder.cpp @@ -9,6 +9,7 @@ #include "flang/lower/PFTBuilder.h" #include "flang/parser/dump-parse-tree.h" #include "flang/parser/parse-tree-visitor.h" +#include "llvm/ADT/DenseMap.h" #include #include #include @@ -74,20 +75,11 @@ class PFTBuilder { template constexpr bool Pre(const A &a) { + bool visit{true}; if constexpr (PFT::isFunctionLike) { return enterFunc(a); } else if constexpr (PFT::isConstruct) { return enterConstruct(a); - } - return true; - } - - template - constexpr void Post(const A &a) { - if constexpr (PFT::isFunctionLike) { - exitFunc(); - } else if constexpr (PFT::isConstruct) { - exitConstruct(); } else if constexpr (UnwrapStmt::isStmt) { using T = typename UnwrapStmt::Type; // Node "a" being visited has one of the following types: @@ -97,10 +89,22 @@ class PFTBuilder { if constexpr (PFT::isConstructStmt || PFT::isOtherStmt) { addEval(PFT::Evaluation{stmt.unwrapped, parents.back(), stmt.pos, stmt.lab}); + visit = false; } else if constexpr (std::is_same_v) { addEval(makeEvalAction(stmt.unwrapped, stmt.pos, stmt.lab)); + visit = false; } } + return visit; + } + + template + constexpr void Post(const A &) { + if constexpr (PFT::isFunctionLike) { + exitFunc(); + } else if constexpr (PFT::isConstruct) { + exitConstruct(); + } } // Module like @@ -111,38 +115,43 @@ class PFTBuilder { void Post(const parser::Submodule &) { exitModule(); } // Block data - void Post(const parser::BlockData &node) { + bool Pre(const parser::BlockData &node) { addUnit(PFT::BlockDataUnit{node, parents.back()}); + return false; } // Get rid of production wrapper - void Post(const parser::UnlabeledStatement - &statement) { + bool Pre(const parser::UnlabeledStatement + &statement) { addEval(std::visit( [&](const auto &x) { return PFT::Evaluation{x, parents.back(), statement.source, {}}; }, statement.statement.u)); + return false; } - void Post(const parser::Statement &statement) { + bool Pre(const parser::Statement &statement) { addEval(std::visit( [&](const auto &x) { return PFT::Evaluation{x, parents.back(), statement.source, statement.label}; }, statement.statement.u)); + return false; } - void Post(const parser::WhereBodyConstruct &whereBody) { - std::visit(common::visitors{ - [&](const parser::Statement &stmt) { - // Not caught as other AssignmentStmt because it is not - // wrapped in a parser::ActionStmt. - addEval(PFT::Evaluation{stmt.statement, parents.back(), - stmt.source, stmt.label}); - }, - [&](const auto &) { /* Already handled*/ }, - }, - whereBody.u); + bool Pre(const parser::WhereBodyConstruct &whereBody) { + return std::visit( + common::visitors{ + [&](const parser::Statement &stmt) { + // Not caught as other AssignmentStmt because it is not + // wrapped in a parser::ActionStmt. + addEval(PFT::Evaluation{stmt.statement, parents.back(), + stmt.source, stmt.label}); + return false; + }, + [&](const auto &) { return true; }, + }, + whereBody.u); } private: @@ -467,109 +476,156 @@ inline void annotateFuncCFG(PFT::FunctionLikeUnit &functionLikeUnit) { annotateFuncCFG(internalFunc); } -llvm::StringRef evalName(PFT::Evaluation &eval) { - return eval.visit(common::visitors{ - [](const PFT::CGJump) { return "CGJump"; }, - [](const auto &parseTreeNode) { - return parser::ParseTreeDumper::GetNodeName(parseTreeNode); - }, - }); -} +class PFTDumper { +public: + void dumpPFT(llvm::raw_ostream &outputStream, PFT::Program &pft) { + outputStream << "PFT root node:" << getNodeIndex(pft) << "\n"; + for (auto &unit : pft.getUnits()) { + std::visit(common::visitors{ + [&](PFT::BlockDataUnit &unit) { + outputStream << getNodeIndex(unit) << " "; + outputStream << "BlockData: "; + dumpParentInfo(outputStream, unit); + outputStream << "\nEndBlockData\n\n"; + }, + [&](PFT::FunctionLikeUnit &func) { + dumpFunctionLikeUnit(outputStream, func); + }, + [&](PFT::ModuleLikeUnit &unit) { + dumpModuleLikeUnit(outputStream, unit); + }, + }, + unit); + } + resetIndexes(); + } + llvm::StringRef evalName(PFT::Evaluation &eval) { + return eval.visit(common::visitors{ + [](const PFT::CGJump) { return "CGJump"; }, + [](const auto &parseTreeNode) { + return parser::ParseTreeDumper::GetNodeName(parseTreeNode); + }, + }); + } -template -void dumpParentInfo(llvm::raw_ostream &stream, const A &evalOrUnit) { - stream << " node:" << static_cast(&evalOrUnit) << " parent:"; - std::visit( - common::visitors{ - [&stream](const auto *parent) { - stream << static_cast(parent); - }, - }, - evalOrUnit.parent.p); -} + template + void dumpParentInfo(llvm::raw_ostream &stream, const A &evalOrUnit) { + stream << " parent:"; + std::visit( + common::visitors{ + [&](const auto *parent) { stream << getNodeIndex(*parent); }, + }, + evalOrUnit.parent.p); + stream << " "; + } -void dumpEvalList(llvm::raw_ostream &outputStream, - PFT::EvaluationCollection &evaluationCollection, - int indent = 1) { - static const std::string white{" ++"}; - std::string indentString{white.substr(0, indent * 2)}; - for (PFT::Evaluation &eval : evaluationCollection) { - llvm::StringRef name{evalName(eval)}; - if (auto *subs{eval.getConstructEvals()}) { - outputStream << indentString << "<<" << name << ">>"; - dumpParentInfo(outputStream, eval); - outputStream << "\n"; - dumpEvalList(outputStream, *subs, indent + 1); - outputStream << indentString << "<>\n"; - } else { - outputStream << indentString << name << ": " << eval.pos.ToString(); - dumpParentInfo(outputStream, eval); - outputStream << "\n"; + void dumpEvalList(llvm::raw_ostream &outputStream, + PFT::EvaluationCollection &evaluationCollection, + int indent = 1) { + static const std::string white{" ++"}; + std::string indentString{white.substr(0, indent * 2)}; + for (PFT::Evaluation &eval : evaluationCollection) { + outputStream << indentString << getNodeIndex(eval) << " "; + llvm::StringRef name{evalName(eval)}; + if (auto *subs{eval.getConstructEvals()}) { + outputStream << "<<" << name << ">>"; + dumpParentInfo(outputStream, eval); + outputStream << "\n"; + dumpEvalList(outputStream, *subs, indent + 1); + outputStream << indentString << "<>\n"; + } else { + outputStream << name; + dumpParentInfo(outputStream, eval); + outputStream << ": " << eval.pos.ToString() + "\n"; + } } } -} -void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, - PFT::FunctionLikeUnit &functionLikeUnit) { - llvm::StringRef unitKind{}; - std::string name{}; - std::string header{}; - std::visit( - common::visitors{ - [&](const parser::Statement *statement) { - unitKind = "Program"; - name = statement->statement.v.ToString(); - }, - [&](const parser::Statement *statement) { - unitKind = "Function"; - name = std::get(statement->statement.t).ToString(); - header = statement->source.ToString(); - }, - [&](const parser::Statement *statement) { - unitKind = "Subroutine"; - name = std::get(statement->statement.t).ToString(); - header = statement->source.ToString(); - }, - [&](const parser::Statement *statement) { - unitKind = "MpSubprogram"; - name = statement->statement.v.ToString(); - header = statement->source.ToString(); - }, - [&](auto *) { - if (std::get_if *>( - &functionLikeUnit.funStmts.back())) { + void dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, + PFT::FunctionLikeUnit &functionLikeUnit) { + outputStream << getNodeIndex(functionLikeUnit) << " "; + llvm::StringRef unitKind{}; + std::string name{}; + std::string header{}; + std::visit( + common::visitors{ + [&](const parser::Statement *statement) { unitKind = "Program"; - name = ""; - } else { - unitKind = ">>>>> Error - no program unit <<<<<"; - } - }, - }, - functionLikeUnit.funStmts.front()); - outputStream << unitKind << ' ' << name; - dumpParentInfo(outputStream, functionLikeUnit); - if (header.size()) - outputStream << ": " << header; - outputStream << '\n'; - dumpEvalList(outputStream, functionLikeUnit.evals); - if (!functionLikeUnit.funcs.empty()) { + name = statement->statement.v.ToString(); + }, + [&](const parser::Statement *statement) { + unitKind = "Function"; + name = std::get(statement->statement.t).ToString(); + header = statement->source.ToString(); + }, + [&](const parser::Statement *statement) { + unitKind = "Subroutine"; + name = std::get(statement->statement.t).ToString(); + header = statement->source.ToString(); + }, + [&](const parser::Statement *statement) { + unitKind = "MpSubprogram"; + name = statement->statement.v.ToString(); + header = statement->source.ToString(); + }, + [&](auto *) { + if (std::get_if + *>(&functionLikeUnit.funStmts.back())) { + unitKind = "Program"; + name = ""; + } else { + unitKind = ">>>>> Error - no program unit <<<<<"; + } + }, + }, + functionLikeUnit.funStmts.front()); + outputStream << unitKind << ' ' << name; + dumpParentInfo(outputStream, functionLikeUnit); + if (header.size()) + outputStream << ": " << header; + outputStream << '\n'; + dumpEvalList(outputStream, functionLikeUnit.evals); + if (!functionLikeUnit.funcs.empty()) { + outputStream << "\nContains\n"; + for (auto &func : functionLikeUnit.funcs) + dumpFunctionLikeUnit(outputStream, func); + outputStream << "EndContains\n"; + } + outputStream << "End" << unitKind << ' ' << name << "\n\n"; + } + + void dumpModuleLikeUnit(llvm::raw_ostream &outputStream, + PFT::ModuleLikeUnit &moduleLikeUnit) { + outputStream << getNodeIndex(moduleLikeUnit) << " "; + outputStream << "ModuleLike: "; + dumpParentInfo(outputStream, moduleLikeUnit); outputStream << "\nContains\n"; - for (auto &func : functionLikeUnit.funcs) + for (auto &func : moduleLikeUnit.funcs) dumpFunctionLikeUnit(outputStream, func); - outputStream << "EndContains\n"; + outputStream << "EndContains\nEndModuleLike\n\n"; } - outputStream << "End" << unitKind << ' ' << name << "\n\n"; -} -void dumpModuleLikeUnit(llvm::raw_ostream &outputStream, - PFT::ModuleLikeUnit &moduleLikeUnit) { - outputStream << "ModuleLike: "; - dumpParentInfo(outputStream, moduleLikeUnit); - outputStream << "\nContains\n"; - for (auto &func : moduleLikeUnit.funcs) - dumpFunctionLikeUnit(outputStream, func); - outputStream << "EndContains\nEndModuleLike\n\n"; -} + template + std::size_t getNodeIndex(const T &node) { + auto addr{static_cast(&node)}; + auto it{nodeIndexes.find(addr)}; + if (it != nodeIndexes.end()) { + return it->second; + } + nodeIndexes.try_emplace(addr, nextIndex); + return nextIndex++; + } + std::size_t getNodeIndex(const PFT::Program &) { return 0; } + + void resetIndexes() { + nodeIndexes.clear(); + nextIndex = 1; + } + +private: + llvm::DenseMap nodeIndexes; + std::size_t nextIndex{1}; // 0 is the root +}; } // namespace @@ -654,23 +710,7 @@ void annotateControl(PFT::Program &pft) { /// Dump an PFT. void dumpPFT(llvm::raw_ostream &outputStream, PFT::Program &pft) { - outputStream << "PFT root node:" << static_cast(&pft) << "\n"; - for (auto &unit : pft.getUnits()) { - std::visit(common::visitors{ - [&](PFT::BlockDataUnit &unit) { - outputStream << "BlockData: "; - dumpParentInfo(outputStream, unit); - outputStream << "\nEndBlockData\n\n"; - }, - [&](PFT::FunctionLikeUnit &func) { - dumpFunctionLikeUnit(outputStream, func); - }, - [&](PFT::ModuleLikeUnit &unit) { - dumpModuleLikeUnit(outputStream, unit); - }, - }, - unit); - } + PFTDumper{}.dumpPFT(outputStream, pft); } } // namespace Fortran::lower diff --git a/test-lit/lower/pre-fir-tree01.f90 b/test-lit/lower/pre-fir-tree01.f90 index 7969ec210756..4a6f3b39bfd3 100644 --- a/test-lit/lower/pre-fir-tree01.f90 +++ b/test-lit/lower/pre-fir-tree01.f90 @@ -2,33 +2,33 @@ ! Test structure of the Pre-FIR tree -! CHECK: PFT root node:0x[[#%x, ROOT:]] -! CHECK: Subroutine foo{{.*}} node:0x[[#%x, FOO:]] parent:0x[[#ROOT]] +! CHECK: PFT root node:[[#%u, ROOT:]] +! CHECK: [[#%u, FOO:]]{{.*}}Subroutine foo{{.*}}parent:[[#ROOT]] subroutine foo() - ! CHECK: <>{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#FOO]] - ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: [[#%u, DO1:]]{{.*}}<>{{.*}}parent:[[#FOO]] + ! CHECK: NonLabelDoStmt{{.*}}parent:[[#DO1]] do i=1,5 - ! CHECK: PrintStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: PrintStmt{{.*}}parent:[[#DO1]] print *, "hey" - ! CHECK: <>{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#DO1]] + ! CHECK: [[#%u, DO2:]]{{.*}}<>{{.*}}parent:[[#DO1]] do j=1,5 - ! CHECK: PrintStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: PrintStmt{{.*}}parent:[[#DO2]] print *, "hello", i, j - ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: EndDoStmt{{.*}}parent:[[#DO2]] end do - ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: EndDoStmt{{.*}}parent:[[#DO1]] end do ! CHECK: EndSubroutine end subroutine -! CHECK: BlockData{{.*}} parent:0x[[#ROOT]] +! CHECK: BlockData{{.*}}parent:[[#ROOT]] block data integer, parameter :: n = 100 integer, dimension(n) :: a, b, c common /arrays/ a, b, c end -! CHECK: ModuleLike{{.*}} node:0x[[#%x, TEST_MOD:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, TEST_MOD:]]{{.*}}ModuleLike{{.*}}parent:[[#ROOT]] module test_mod interface ! check specification parts are not part of the PFT. @@ -39,75 +39,75 @@ module subroutine dump() integer :: xdim real, allocatable :: pressure(:) contains - ! CHECK: Subroutine foo{{.*}} node:0x[[#%x, M_FOO:]] parent:0x[[#TEST_MOD]] + ! CHECK: [[#%u, M_FOO:]]{{.*}}Subroutine foo{{.*}}parent:[[#TEST_MOD]] subroutine foo() contains - ! CHECK: Subroutine subfoo{{.*}} node:0x[[#%x, SUBFOO:]] parent:0x[[#M_FOO]] + ! CHECK: [[#%u, SUBFOO:]]{{.*}}Subroutine subfoo{{.*}}parent:[[#M_FOO]] subroutine subfoo() end subroutine - ! CHECK: Function subfoo2{{.*}} node:0x[[#%x, SUBFOO2:]] parent:0x[[#M_FOO]] + ! CHECK: [[#%u, SUBFOO2:]]{{.*}}Function subfoo2{{.*}}parent:[[#M_FOO]] function subfoo2() end function end subroutine - ! CHECK: Function foo2{{.*}} node:0x[[#%x, M_FOO2:]] parent:0x[[#TEST_MOD]] + ! CHECK: [[#%u, M_FOO2:]]{{.*}}Function foo2{{.*}}parent:[[#TEST_MOD]] function foo2(i, j) integer i, j, foo2 - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#M_FOO2]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#M_FOO2]] foo2 = i + j contains - ! CHECK: Subroutine subfoo{{.*}} node:0x[[#%x, SUBFOO:]] parent:0x[[#M_FOO2]] + ! CHECK: [[#%u, SUBFOO:]]{{.*}}Subroutine subfoo{{.*}}parent:[[#M_FOO2]] subroutine subfoo() end subroutine end function end module -! CHECK: ModuleLike{{.*}} node:0x[[#%x, SUB_MOD:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, SUB_MOD:]]{{.*}}ModuleLike{{.*}}parent:[[#ROOT]] submodule (test_mod) test_mod_impl contains - ! CHECK: Subroutine foo{{.*}} node:0x[[#%x, SUBM_FOO:]] parent:0x[[#SUB_MOD]] + ! CHECK: [[#%u, SUBM_FOO:]]{{.*}}Subroutine foo{{.*}}parent:[[#SUB_MOD]] subroutine foo() contains - ! CHECK: Subroutine subfoo{{.*}} node:0x[[#%x, SUBFOO:]] parent:0x[[#SUBM_FOO]] + ! CHECK: [[#%u, SUBFOO:]]{{.*}}Subroutine subfoo{{.*}}parent:[[#SUBM_FOO]] subroutine subfoo() end subroutine - ! CHECK: Function subfoo2{{.*}} node:0x[[#%x, SUBFOO2:]] parent:0x[[#SUBM_FOO]] + ! CHECK: [[#%u, SUBFOO2:]]{{.*}}Function subfoo2{{.*}}parent:[[#SUBM_FOO]] function subfoo2() end function end subroutine - ! CHECK: MpSubprogram dump{{.*}} node:0x[[#%x, MP_DUMP:]] parent:0x[[#SUB_MOD]] + ! CHECK: [[#%u, MP_DUMP:]]{{.*}}MpSubprogram dump{{.*}}parent:[[#SUB_MOD]] module procedure dump - ! CHECK: FormatStmt{{.*}} parent:0x[[#MP_DUMP]] + ! CHECK: FormatStmt{{.*}}parent:[[#MP_DUMP]] 11 format (2E16.4, I6) - ! CHECK: <>{{.*}} node:0x[[#%x, IF1:]] parent:0x[[#MP_DUMP]] - ! CHECK: IfThenStmt{{.*}} parent:0x[[#IF1]] + ! CHECK: [[#%u, IF1:]]{{.*}}<>{{.*}}parent:[[#MP_DUMP]] + ! CHECK: IfThenStmt{{.*}}parent:[[#IF1]] if (xdim > 100) then - ! CHECK: PrintStmt{{.*}} parent:0x[[#IF1]] + ! CHECK: PrintStmt{{.*}}parent:[[#IF1]] print *, "test: ", xdim - ! CHECK: ElseStmt{{.*}} parent:0x[[#IF1]] + ! CHECK: ElseStmt{{.*}}parent:[[#IF1]] else - ! CHECK: WriteStmt{{.*}} parent:0x[[#IF1]] + ! CHECK: WriteStmt{{.*}}parent:[[#IF1]] write (*, 11) "test: ", xdim, pressure - ! CHECK: EndIfStmt{{.*}} parent:0x[[#IF1]] + ! CHECK: EndIfStmt{{.*}}parent:[[#IF1]] end if end procedure end submodule -! CHECK: BlockData{{.*}} parent:0x[[#ROOT]] +! CHECK: BlockData{{.*}}parent:[[#ROOT]] block data integer i, j, k common /indexes/ i, j, k end -! CHECK: Function bar{{.*}} node:0x[[#%x, BAR:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, BAR:]]{{.*}}Function bar{{.*}}parent:[[#ROOT]] function bar() end function -! CHECK: Program {{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, PROG:]]{{.*}}Program {{.*}}parent:[[#ROOT]] ! check specification parts are not part of the PFT. ! CHECK-NOT: node use test_mod real, allocatable :: x(:) - ! CHECK: AllocateStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: AllocateStmt{{.*}}parent:[[#PROG]] allocate(x(foo2(10, 30))) end diff --git a/test-lit/lower/pre-fir-tree02.f90 b/test-lit/lower/pre-fir-tree02.f90 index c2c792b2b25d..518326f14f0b 100644 --- a/test-lit/lower/pre-fir-tree02.f90 +++ b/test-lit/lower/pre-fir-tree02.f90 @@ -3,8 +3,8 @@ ! Test Pre-FIR Tree captures all the intended nodes from the parse-tree ! Coarray and OpenMP related nodes are tested in other files. -! CHECK: PFT root node:0x[[#%x, ROOT:]] -! CHECK: Program test_prog{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] +! CHECK: PFT root node:[[#%u, ROOT:]] +! CHECK: [[#%u, PROG:]]{{.*}}Program test_prog{{.*}}parent:[[#ROOT]] program test_prog ! Check specification part is not part of the tree. interface @@ -16,126 +16,126 @@ subroutine incr(i) real, allocatable, target :: x(:) real :: y(100) ! CHECK-NOT: node - ! CHECK: <>{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#PROG]] - ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: [[#%u, DO1:]]{{.*}}<>{{.*}}parent:[[#PROG]] + ! CHECK: NonLabelDoStmt{{.*}}parent:[[#DO1]] do i=1,5 - ! CHECK: PrintStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: PrintStmt{{.*}}parent:[[#DO1]] print *, "hey" - ! CHECK: <>{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#DO1]] - ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: [[#%u, DO2:]]{{.*}}<>{{.*}}parent:[[#DO1]] + ! CHECK: NonLabelDoStmt{{.*}}parent:[[#DO2]] do j=1,5 - ! CHECK: PrintStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: PrintStmt{{.*}}parent:[[#DO2]] print *, "hello", i, j - ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: EndDoStmt{{.*}}parent:[[#DO2]] end do - ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: EndDoStmt{{.*}}parent:[[#DO1]] end do - ! CHECK: <>{{.*}} node:0x[[#%x, ASSOC:]] parent:0x[[#PROG]] - ! CHECK: AssociateStmt{{.*}} parent:0x[[#ASSOC]] + ! CHECK: [[#%u, ASSOC:]]{{.*}}<>{{.*}}parent:[[#PROG]] + ! CHECK: AssociateStmt{{.*}}parent:[[#ASSOC]] associate (k => i + j) - ! CHECK: AllocateStmt{{.*}} parent:0x[[#ASSOC]] + ! CHECK: AllocateStmt{{.*}}parent:[[#ASSOC]] allocate(x(k)) - ! CHECK: EndAssociateStmt{{.*}} parent:0x[[#ASSOC]] + ! CHECK: EndAssociateStmt{{.*}}parent:[[#ASSOC]] end associate - ! CHECK: <>{{.*}} node:0x[[#%x, BLOCK:]] parent:0x[[#PROG]] - ! CHECK: BlockStmt{{.*}} parent:0x[[#BLOCK]] + ! CHECK: [[#%u, BLOCK:]]{{.*}}<>{{.*}}parent:[[#PROG]] + ! CHECK: BlockStmt{{.*}}parent:[[#BLOCK]] block integer :: k, l real, pointer :: p(:) - ! CHECK: PointerAssignmentStmt{{.*}} parent:0x[[#BLOCK]] + ! CHECK: PointerAssignmentStmt{{.*}}parent:[[#BLOCK]] p => x - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#BLOCK]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#BLOCK]] k = size(p) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#BLOCK]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#BLOCK]] l = 1 - ! CHECK: <>{{.*}} node:0x[[#%x, SELECTCASE:]] parent:0x[[#BLOCK]] - ! CHECK: SelectCaseStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: [[#%u, SELECTCASE:]]{{.*}}<>{{.*}}parent:[[#BLOCK]] + ! CHECK: SelectCaseStmt{{.*}}parent:[[#SELECTCASE]] select case (k) - ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: CaseStmt{{.*}}parent:[[#SELECTCASE]] case (:0) - ! CHECK: NullifyStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: NullifyStmt{{.*}}parent:[[#SELECTCASE]] nullify(p) - ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: CaseStmt{{.*}}parent:[[#SELECTCASE]] case (1) - ! CHECK: <>{{.*}} node:0x[[#%x, IFTHEN:]] parent:0x[[#SELECTCASE]] - ! CHECK: IfThenStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: [[#%u, IFTHEN:]]{{.*}}<>{{.*}}parent:[[#SELECTCASE]] + ! CHECK: IfThenStmt{{.*}}parent:[[#IFTHEN]] if (p(1)>0.) then - ! CHECK: PrintStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: PrintStmt{{.*}}parent:[[#IFTHEN]] print *, "+" - ! CHECK: ElseIfStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: ElseIfStmt{{.*}}parent:[[#IFTHEN]] else if (p(1)==0.) then - ! CHECK: PrintStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: PrintStmt{{.*}}parent:[[#IFTHEN]] print *, "0." - ! CHECK: ElseStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: ElseStmt{{.*}}parent:[[#IFTHEN]] else - ! CHECK: PrintStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: PrintStmt{{.*}}parent:[[#IFTHEN]] print *, "-" - ! CHECK: EndIfStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: EndIfStmt{{.*}}parent:[[#IFTHEN]] end if - ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: CaseStmt{{.*}}parent:[[#SELECTCASE]] case (2:10) - ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: CaseStmt{{.*}}parent:[[#SELECTCASE]] case default ! Note: label-do-loop are canonicalized into do constructs - ! CHECK: <>{{.*}} node:0x[[#%x, DO3:]] parent:0x[[#SELECTCASE]] - ! CHECK: NonLabelDoStmt{{.*}} parent:0x[[#DO3]] + ! CHECK: [[#%u, DO3:]]{{.*}}<>{{.*}}parent:[[#SELECTCASE]] + ! CHECK: NonLabelDoStmt{{.*}}parent:[[#DO3]] do 22 while(l<=k) - ! CHECK: IfStmt{{.*}} parent:0x[[#DO3]] + ! CHECK: IfStmt{{.*}}parent:[[#DO3]] if (p(l)<0.) p(l)=cos(p(l)) - ! CHECK: CallStmt{{.*}} parent:0x[[#DO3]] + ! CHECK: CallStmt{{.*}}parent:[[#DO3]] 22 call incr(l) - ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO3]] - ! CHECK: CaseStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: EndDoStmt{{.*}}parent:[[#DO3]] + ! CHECK: CaseStmt{{.*}}parent:[[#SELECTCASE]] case (100:) - ! CHECK: EndSelectStmt{{.*}} parent:0x[[#SELECTCASE]] + ! CHECK: EndSelectStmt{{.*}}parent:[[#SELECTCASE]] end select - ! CHECK: EndBlockStmt{{.*}} parent:0x[[#BLOCK]] + ! CHECK: EndBlockStmt{{.*}}parent:[[#BLOCK]] end block ! CHECK-NOT: WhereConstruct - ! CHECK: WhereStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: WhereStmt{{.*}}parent:[[#PROG]] where (x > 1.) x = x/2. - ! CHECK: <>{{.*}} node:0x[[#%x, WHERE:]] parent:0x[[#PROG]] - ! CHECK: WhereConstructStmt{{.*}} parent:0x[[#WHERE]] + ! CHECK: [[#%u, WHERE:]]{{.*}}<>{{.*}}parent:[[#PROG]] + ! CHECK: WhereConstructStmt{{.*}}parent:[[#WHERE]] where (x == 0.) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#WHERE]] x = 0.01 - ! CHECK: MaskedElsewhereStmt{{.*}} parent:0x[[#WHERE]] + ! CHECK: MaskedElsewhereStmt{{.*}}parent:[[#WHERE]] elsewhere (x < 0.5) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#WHERE]] x = x*2. - ! CHECK: <>{{.*}} node:0x[[#%x, WHERE2:]] parent:0x[[#WHERE]] + ! CHECK: [[#%u, WHERE2:]]{{.*}}<>{{.*}}parent:[[#WHERE]] where (y > 0.4) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE2]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#WHERE2]] y = y/2. end where - ! CHECK: ElsewhereStmt{{.*}} parent:0x[[#WHERE]] + ! CHECK: ElsewhereStmt{{.*}}parent:[[#WHERE]] elsewhere - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#WHERE]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#WHERE]] x = x + 1. - ! CHECK: EndWhereStmt{{.*}} parent:0x[[#WHERE]] + ! CHECK: EndWhereStmt{{.*}}parent:[[#WHERE]] end where ! CHECK-NOT: ForAllConstruct - ! CHECK: ForallStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: ForallStmt{{.*}}parent:[[#PROG]] forall (i = 1:5) x = y(i) - ! CHECK: <>{{.*}} node:0x[[#%x, FORALL:]] parent:0x[[#PROG]] - ! CHECK: ForallConstructStmt{{.*}} parent:0x[[#FORALL]] + ! CHECK: [[#%u, FORALL:]]{{.*}}<>{{.*}}parent:[[#PROG]] + ! CHECK: ForallConstructStmt{{.*}}parent:[[#FORALL]] forall (i = 1:5) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#FORALL]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#FORALL]] x(i) = x(i) + y(10*i) - ! CHECK: EndForallStmt{{.*}} parent:0x[[#FORALL]] + ! CHECK: EndForallStmt{{.*}}parent:[[#FORALL]] end forall - ! CHECK: DeallocateStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: DeallocateStmt{{.*}}parent:[[#PROG]] deallocate(x) end -! CHECK: ModuleLike{{.*}} node:0x[[#%x, MOD:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, MOD:]]{{.*}}ModuleLike{{.*}}parent:[[#ROOT]] module test type :: a_type integer :: x @@ -144,76 +144,76 @@ module test integer :: y end type contains - ! CHECK: Function foo{{.*}} node:0x[[#%x, FOO:]] parent:0x[[#MOD]] + ! CHECK: [[#%u, FOO:]]{{.*}}Function foo{{.*}}parent:[[#MOD]] function foo(x) real x(..) integer :: foo - ! CHECK: <>{{.*}} node:0x[[#%x, SELECTRANK:]] parent:0x[[#FOO]] - ! CHECK: SelectRankStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: [[#%u, SELECTRANK:]]{{.*}}<>{{.*}}parent:[[#FOO]] + ! CHECK: SelectRankStmt{{.*}}parent:[[#SELECTRANK]] select rank(x) - ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: SelectRankCaseStmt{{.*}}parent:[[#SELECTRANK]] rank (0) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#SELECTRANK]] foo = 0 - ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: SelectRankCaseStmt{{.*}}parent:[[#SELECTRANK]] rank (*) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#SELECTRANK]] foo = -1 - ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: SelectRankCaseStmt{{.*}}parent:[[#SELECTRANK]] rank (1) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#SELECTRANK]] foo = 1 - ! CHECK: SelectRankCaseStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: SelectRankCaseStmt{{.*}}parent:[[#SELECTRANK]] rank default - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#SELECTRANK]] foo = 2 - ! CHECK: EndSelectStmt{{.*}} parent:0x[[#SELECTRANK]] + ! CHECK: EndSelectStmt{{.*}}parent:[[#SELECTRANK]] end select end function - ! CHECK: Function bar{{.*}} node:0x[[#%x, BAR:]] parent:0x[[#MOD]] + ! CHECK: [[#%u, BAR:]]{{.*}}Function bar{{.*}}parent:[[#MOD]] function bar(x) class(*) :: x - ! CHECK: <>{{.*}} node:0x[[#%x, SELECTTYPE:]] parent:0x[[#BAR]] - ! CHECK: SelectTypeStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: [[#%u, SELECTTYPE:]]{{.*}}<>{{.*}}parent:[[#BAR]] + ! CHECK: SelectTypeStmt{{.*}}parent:[[#SELECTTYPE]] select type(x) - ! CHECK: TypeGuardStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: TypeGuardStmt{{.*}}parent:[[#SELECTTYPE]] type is (integer) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#SELECTTYPE]] bar = 0 - ! CHECK: TypeGuardStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: TypeGuardStmt{{.*}}parent:[[#SELECTTYPE]] class is (a_type) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#SELECTTYPE]] bar = 1 - ! CHECK: ReturnStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: ReturnStmt{{.*}}parent:[[#SELECTTYPE]] return - ! CHECK: TypeGuardStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: TypeGuardStmt{{.*}}parent:[[#SELECTTYPE]] class default - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#SELECTTYPE]] bar = -1 - ! CHECK: EndSelectStmt{{.*}} parent:0x[[#SELECTTYPE]] + ! CHECK: EndSelectStmt{{.*}}parent:[[#SELECTTYPE]] end select end function - ! CHECK: Subroutine sub{{.*}} node:0x[[#%x, SUB:]] parent:0x[[#MOD]] + ! CHECK: [[#%u, SUB:]]{{.*}}Subroutine sub{{.*}}parent:[[#MOD]] subroutine sub(a) real(4):: a ! CompilerDirective - ! CHECK: <>{{.*}} parent:0x[[#SUB]] + ! CHECK: <>{{.*}}parent:[[#SUB]] !DIR$ IGNORE_TKR a end subroutine end module -! CHECK: Subroutine altreturn{{.*}} node:0x[[#%x, ALTSUB:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, ALTSUB:]]{{.*}}Subroutine altreturn{{.*}}parent:[[#ROOT]] subroutine altreturn(i, j, *, *) - ! CHECK: <>{{.*}} node:0x[[#%x, IFTHEN:]] parent:0x[[#ALTSUB]] + ! CHECK: [[#%u, IFTHEN:]]{{.*}}<>{{.*}}parent:[[#ALTSUB]] if (i>j) then - ! CHECK: ReturnStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: ReturnStmt{{.*}}parent:[[#IFTHEN]] return 1 else - ! CHECK: ReturnStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: ReturnStmt{{.*}}parent:[[#IFTHEN]] return 2 end if end subroutine @@ -221,99 +221,99 @@ subroutine altreturn(i, j, *, *) ! Remaining TODO -! CHECK: Subroutine iostmts{{.*}} node:0x[[#%x, IO:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, IO:]]{{.*}}Subroutine iostmts{{.*}}parent:[[#ROOT]] subroutine iostmts(filename, a, b, c) character(*) :: filename integer :: length logical :: file_is_opened real, a, b ,c - ! CHECK: InquireStmt{{.*}} parent:0x[[#]] + ! CHECK: InquireStmt{{.*}}parent:[[#]] inquire(file=filename, opened=file_is_opened) - ! CHECK: <>{{.*}} node:0x[[#%x, IFTHEN:]] parent:0x[[#IO]] + ! CHECK: [[#%u, IFTHEN:]]{{.*}}<>{{.*}}parent:[[#IO]] if (file_is_opened) then - ! CHECK: OpenStmt{{.*}} parent:0x[[#IFTHEN]] + ! CHECK: OpenStmt{{.*}}parent:[[#IFTHEN]] open(10, FILE=filename) end if - ! CHECK: ReadStmt{{.*}} parent:0x[[#IO]] + ! CHECK: ReadStmt{{.*}}parent:[[#IO]] read(10, *) length - ! CHECK: RewindStmt{{.*}} parent:0x[[#IO]] + ! CHECK: RewindStmt{{.*}}parent:[[#IO]] rewind 10 - ! CHECK: NamelistStmt{{.*}} parent:0x[[#IO]] + ! CHECK: NamelistStmt{{.*}}parent:[[#IO]] namelist /nlist/ a, b, c - ! CHECK: WriteStmt{{.*}} parent:0x[[#IO]] + ! CHECK: WriteStmt{{.*}}parent:[[#IO]] write(10, NML=nlist) - ! CHECK: BackspaceStmt{{.*}} parent:0x[[#IO]] + ! CHECK: BackspaceStmt{{.*}}parent:[[#IO]] backspace(10) - ! CHECK: FormatStmt{{.*}} parent:0x[[#IO]] + ! CHECK: FormatStmt{{.*}}parent:[[#IO]] 1 format (1PE12.4) - ! CHECK: WriteStmt{{.*}} parent:0x[[#IO]] + ! CHECK: WriteStmt{{.*}}parent:[[#IO]] write (10, 1) a - ! CHECK: EndfileStmt{{.*}} parent:0x[[#IO]] + ! CHECK: EndfileStmt{{.*}}parent:[[#IO]] endfile 10 - ! CHECK: FlushStmt{{.*}} parent:0x[[#IO]] + ! CHECK: FlushStmt{{.*}}parent:[[#IO]] flush 10 - ! CHECK: WaitStmt{{.*}} parent:0x[[#IO]] + ! CHECK: WaitStmt{{.*}}parent:[[#IO]] wait(10) - ! CHECK: CloseStmt{{.*}} parent:0x[[#IO]] + ! CHECK: CloseStmt{{.*}}parent:[[#IO]] close(10) end subroutine -! CHECK: Subroutine sub2{{.*}} node:0x[[#%x, SUB2:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, SUB2:]]{{.*}}Subroutine sub2{{.*}}parent:[[#ROOT]] subroutine sub2() integer :: i, j, k, l i = 0 1 j = i - ! CHECK: ContinueStmt{{.*}} parent:0x[[#SUB2]] + ! CHECK: ContinueStmt{{.*}}parent:[[#SUB2]] 2 continue i = i+1 3 j = j+1 -! CHECK: ArithmeticIfStmt{{.*}} parent:0x[[#SUB2]] +! CHECK: ArithmeticIfStmt{{.*}}parent:[[#SUB2]] if (j-i) 3, 4, 5 - ! CHECK: GotoStmt{{.*}} parent:0x[[#SUB2]] + ! CHECK: GotoStmt{{.*}}parent:[[#SUB2]] 4 goto 6 ! FIXME: is name resolution on assigned goto broken/todo ? -! WILLCHECK: AssignStmt{{.*}} parent:0x[[#SUB2]] +! WILLCHECK: AssignStmt{{.*}}parent:[[#SUB2]] !55 assign 6 to label -! WILLCHECK: AssignedGotoStmt{{.*}} parent:0x[[#SUB2]] +! WILLCHECK: AssignedGotoStmt{{.*}}parent:[[#SUB2]] !66 go to label (5, 6) -! CHECK: ComputedGotoStmt{{.*}} parent:0x[[#SUB2]] +! CHECK: ComputedGotoStmt{{.*}}parent:[[#SUB2]] go to (5, 6), 1 + mod(i, 2) 5 j = j + 1 6 i = i + j/2 - ! CHECK: <>{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#SUB2]] + ! CHECK: [[#%u, DO1:]]{{.*}}<>{{.*}}parent:[[#SUB2]] do1: do k=1,10 - ! CHECK: <>{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#DO1]] + ! CHECK: [[#%u, DO2:]]{{.*}}<>{{.*}}parent:[[#DO1]] do2: do l=5,20 - ! CHECK: CycleStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: CycleStmt{{.*}}parent:[[#DO2]] cycle do1 - ! CHECK: ExitStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: ExitStmt{{.*}}parent:[[#DO2]] exit do2 end do do2 end do do1 - ! CHECK: PauseStmt{{.*}} parent:0x[[#SUB2]] + ! CHECK: PauseStmt{{.*}}parent:[[#SUB2]] pause 7 - ! CHECK: StopStmt{{.*}} parent:0x[[#SUB2]] + ! CHECK: StopStmt{{.*}}parent:[[#SUB2]] stop end subroutine -! CHECK: Subroutine sub3{{.*}} node:0x[[#%x, SUB3:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, SUB3:]]{{.*}}Subroutine sub3{{.*}}parent:[[#ROOT]] subroutine sub3() print *, "normal" - ! CHECK: EntryStmt{{.*}} parent:0x[[#SUB3]] + ! CHECK: EntryStmt{{.*}}parent:[[#SUB3]] entry sub4entry() print *, "test" end subroutine -! CHECK: Subroutine sub4{{.*}} node:0x[[#%x, SUB4:]] parent:0x[[#ROOT]] +! CHECK: [[#%u, SUB4:]]{{.*}}Subroutine sub4{{.*}}parent:[[#ROOT]] subroutine sub4(i, j) integer :: i print*, "test" - ! CHECK: DataStmt{{.*}} parent:0x[[#SUB4]] + ! CHECK: DataStmt{{.*}}parent:[[#SUB4]] data i /1/ end subroutine diff --git a/test-lit/lower/pre-fir-tree03.f90 b/test-lit/lower/pre-fir-tree03.f90 index acd73e2a534c..9d0cf1d67e1d 100644 --- a/test-lit/lower/pre-fir-tree03.f90 +++ b/test-lit/lower/pre-fir-tree03.f90 @@ -2,55 +2,55 @@ ! Test Pre-FIR Tree captures OpenMP related constructs -! CHECK: PFT root node:0x[[#%x, ROOT:]] -! CHECK: Program test_omp{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] +! CHECK: PFT root node:[[#%u, ROOT:]] +! CHECK: [[#%u, PROG:]]{{.*}}Program test_omp{{.*}}parent:[[#ROOT]] program test_omp - ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: PrintStmt{{.*}}parent:[[#PROG]] print *, "sequential" - ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_PAR:]] parent:0x[[#PROG]] + ! CHECK: [[#%u, OMP_PAR:]]{{.*}}OpenMPConstruct{{.*}}parent:[[#PROG]] !$omp parallel - ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_PAR]] + ! CHECK: PrintStmt{{.*}}parent:[[#OMP_PAR]] print *, "in omp //" - ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_LOOP:]] parent:0x[[#OMP_PAR]] + ! CHECK: [[#%u, OMP_LOOP:]]{{.*}}OpenMPConstruct{{.*}}parent:[[#OMP_PAR]] !$omp do - ! CHECK: DoConstruct{{.*}} node:0x[[#%x, DO1:]] parent:0x[[#OMP_LOOP]] - ! CHECK: LabelDoStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: [[#%u, DO1:]]{{.*}}DoConstruct{{.*}}parent:[[#OMP_LOOP]] + ! CHECK: LabelDoStmt{{.*}}parent:[[#DO1]] do i=1,100 - ! CHECK: PrintStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: PrintStmt{{.*}}parent:[[#DO1]] print *, "in omp do" - ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO1]] + ! CHECK: EndDoStmt{{.*}}parent:[[#DO1]] end do - ! CHECK: OmpEndLoopDirective{{.*}} parent:0x[[#OMP_LOOP]] + ! CHECK: OmpEndLoopDirective{{.*}}parent:[[#OMP_LOOP]] !$omp end do - ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_PAR]] + ! CHECK: PrintStmt{{.*}}parent:[[#OMP_PAR]] print *, "not in omp do" - ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_LOOP2:]] parent:0x[[#OMP_PAR]] + ! CHECK: [[#%u, OMP_LOOP2:]]{{.*}}OpenMPConstruct{{.*}}parent:[[#OMP_PAR]] !$omp do - ! CHECK: DoConstruct{{.*}} node:0x[[#%x, DO2:]] parent:0x[[#OMP_LOOP2]] - ! CHECK: LabelDoStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: [[#%u, DO2:]]{{.*}}DoConstruct{{.*}}parent:[[#OMP_LOOP2]] + ! CHECK: LabelDoStmt{{.*}}parent:[[#DO2]] do i=1,100 - ! CHECK: PrintStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: PrintStmt{{.*}}parent:[[#DO2]] print *, "in omp do" - ! CHECK: EndDoStmt{{.*}} parent:0x[[#DO2]] + ! CHECK: EndDoStmt{{.*}}parent:[[#DO2]] end do ! CHECK-NOT: OmpEndLoopDirective - ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_PAR]] + ! CHECK: PrintStmt{{.*}}parent:[[#OMP_PAR]] print *, "no in omp do" !$omp end parallel - ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: PrintStmt{{.*}}parent:[[#PROG]] print *, "sequential again" - ! CHECK: OpenMPConstruct{{.*}} node:0x[[#%x, OMP_TASK:]] parent:0x[[#PROG]] + ! CHECK: [[#%u, OMP_TASK:]]{{.*}}OpenMPConstruct{{.*}}parent:[[#PROG]] !$omp task - ! CHECK: PrintStmt{{.*}} parent:0x[[#OMP_TASK]] + ! CHECK: PrintStmt{{.*}}parent:[[#OMP_TASK]] print *, "in task" !$omp end task - ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: PrintStmt{{.*}}parent:[[#PROG]] print *, "sequential again" end program diff --git a/test-lit/lower/pre-fir-tree04.f90 b/test-lit/lower/pre-fir-tree04.f90 index a64e1422ca4d..5fc702c0afb6 100644 --- a/test-lit/lower/pre-fir-tree04.f90 +++ b/test-lit/lower/pre-fir-tree04.f90 @@ -2,8 +2,8 @@ ! Test Pre-FIR Tree captures all the coarray related statements -! CHECK: PFT root node:0x[[#%x, ROOT:]] -! CHECK: Subroutine test_coarray{{.*}} node:0x[[#%x, PROG:]] parent:0x[[#ROOT]] +! CHECK: PFT root node:[[#%u, ROOT:]] +! CHECK: [[#%u, PROG:]]{{.*}}Subroutine test_coarray{{.*}}parent:[[#ROOT]] Subroutine test_coarray use iso_fortran_env, only: team_type, event_type, lock_type type(team_type) :: t @@ -12,55 +12,55 @@ Subroutine test_coarray real :: y[10,*] integer :: counter[*] logical :: is_master - ! CHECK: ChangeTeamConstruct{{.*}} node:0x[[#%x, CHANGE_TEAM:]] parent:0x[[#PROG]] + ! CHECK: [[#%u, CHANGE_TEAM:]]{{.*}}ChangeTeamConstruct{{.*}}parent:[[#PROG]] change team(t, x[5,*] => y) - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#CHANGE_TEAM]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#CHANGE_TEAM]] x = x[4, 1] end team - ! CHECK: FormTeamStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: FormTeamStmt{{.*}}parent:[[#PROG]] form team(1, t) - ! CHECK: IfConstruct{{.*}} node:0x[[#%x, IF:]] parent:0x[[#PROG]] + ! CHECK: [[#%u, IF:]]{{.*}}IfConstruct{{.*}}parent:[[#PROG]] if (this_image() == 1) then - ! CHECK: EventPostStmt{{.*}} parent:0x[[#IF]] + ! CHECK: EventPostStmt{{.*}}parent:[[#IF]] event post (done) else - ! CHECK: EventWaitStmt{{.*}} parent:0x[[#IF]] + ! CHECK: EventWaitStmt{{.*}}parent:[[#IF]] event wait (done) end if - ! CHECK: CriticalConstruct{{.*}} node:0x[[#%x, CRITICAL:]] parent:0x[[#PROG]] + ! CHECK: [[#%u, CRITICAL:]]{{.*}}CriticalConstruct{{.*}}parent:[[#PROG]] critical - ! CHECK: AssignmentStmt{{.*}} parent:0x[[#CRITICAL]] + ! CHECK: AssignmentStmt{{.*}}parent:[[#CRITICAL]] counter[1] = counter[1] + 1 end critical - ! CHECK: LockStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: LockStmt{{.*}}parent:[[#PROG]] lock(alock) - ! CHECK: PrintStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: PrintStmt{{.*}}parent:[[#PROG]] print *, "I have the lock" - ! CHECK: UnlockStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: UnlockStmt{{.*}}parent:[[#PROG]] unlock(alock) - ! CHECK: SyncAllStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: SyncAllStmt{{.*}}parent:[[#PROG]] sync all - ! CHECK: SyncMemoryStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: SyncMemoryStmt{{.*}}parent:[[#PROG]] sync memory - ! CHECK: SyncTeamStmt{{.*}} parent:0x[[#PROG]] + ! CHECK: SyncTeamStmt{{.*}}parent:[[#PROG]] sync team(t) - ! CHECK: IfConstruct{{.*}} node:0x[[#%x, IF2:]] parent:0x[[#PROG]] + ! CHECK: [[#%u, IF2:]]{{.*}}IfConstruct{{.*}}parent:[[#PROG]] if (this_image() == 1) then - ! CHECK: SyncImagesStmt{{.*}} parent:0x[[#IF2]] + ! CHECK: SyncImagesStmt{{.*}}parent:[[#IF2]] sync images(*) else - ! CHECK: SyncImagesStmt{{.*}} parent:0x[[#IF2]] + ! CHECK: SyncImagesStmt{{.*}}parent:[[#IF2]] sync images(1) end if - ! CHECK: IfConstruct{{.*}} node:0x[[#%x, IF3:]] parent:0x[[#PROG]] + ! CHECK: [[#%u, IF3:]]{{.*}}IfConstruct{{.*}}parent:[[#PROG]] if (y<0.) then - ! CHECK: FailImageStmt{{.*}} parent:0x[[#IF3]] + ! CHECK: FailImageStmt{{.*}}parent:[[#IF3]] fail image end if end