1717#include "type-parser-implementation.h"
1818#include "flang/Parser/openmp-utils.h"
1919#include "flang/Parser/parse-tree.h"
20+ #include "flang/Parser/tools.h"
2021#include "llvm/ADT/ArrayRef.h"
2122#include "llvm/ADT/Bitset.h"
2223#include "llvm/ADT/STLExtras.h"
3031#include <iterator>
3132#include <list>
3233#include <optional>
34+ #include <set>
3335#include <string>
3436#include <tuple>
3537#include <type_traits>
@@ -56,6 +58,35 @@ constexpr auto endOmpLine = space >> endOfLine;
5658constexpr auto logicalConstantExpr{logical(constantExpr)};
5759constexpr auto scalarLogicalConstantExpr{scalar(logicalConstantExpr)};
5860
61+ // Parser that wraps the result of another parser into a Block. If the given
62+ // parser succeeds, the result is a block containing the ExecutionPartConstruct
63+ // result of the argument parser. Otherwise the parser fails.
64+ template <typename ExecParser> struct AsBlockParser {
65+ using resultType = Block;
66+ static_assert(
67+ std::is_same_v<typename ExecParser::resultType, ExecutionPartConstruct>);
68+
69+ constexpr AsBlockParser(ExecParser epc) : epc_(epc) {}
70+ std::optional<resultType> Parse(ParseState &state) const {
71+ if (auto &&exec{attempt(epc_).Parse(state)}) {
72+ Block body;
73+ body.push_back(std::move(*exec));
74+ return body;
75+ }
76+ return std::nullopt;
77+ }
78+
79+ private:
80+ const ExecParser epc_;
81+ };
82+
83+ template <typename ExecParser,
84+ typename = std::enable_if<std::is_same_v<typename ExecParser::resultType,
85+ ExecutionPartConstruct>>>
86+ constexpr auto asBlock(ExecParser epc) {
87+ return AsBlockParser<ExecParser>(epc);
88+ }
89+
5990// Given a parser for a single element, and a parser for a list of elements
6091// of the same type, create a parser that constructs the entire list by having
6192// the single element be the head of the list, and the rest be the tail.
@@ -1656,6 +1687,110 @@ struct LooselyStructuredBlockParser {
16561687 }
16571688};
16581689
1690+ struct NonBlockDoConstructParser {
1691+ using resultType = Block;
1692+
1693+ std::optional<resultType> Parse(ParseState &state) const {
1694+ std::set<Label> labels;
1695+ Block body;
1696+
1697+ // Parse nests like
1698+ // do 20 i = 1, n LabelDoStmt.t<Label> = 20
1699+ // do 10 j = 1, m
1700+ // ...
1701+ // 10 continue Statement<...>.label = 10
1702+ // 20 continue
1703+
1704+ // Keep parsing ExecutionPartConstructs until the set of open label-do
1705+ // statements becomes empty, or until the EPC parser fails.
1706+ auto processEpc{[&](ExecutionPartConstruct &&epc) {
1707+ if (auto &&label{GetStatementLabel(epc)}) {
1708+ labels.erase(*label);
1709+ }
1710+ if (auto *labelDo{Unwrap<LabelDoStmt>(epc)}) {
1711+ labels.insert(std::get<Label>(labelDo->t));
1712+ }
1713+ body.push_back(std::move(epc));
1714+ }};
1715+
1716+ auto nonBlockDo{predicated(executionPartConstruct,
1717+ [](auto &epc) { return Unwrap<LabelDoStmt>(epc); })};
1718+
1719+ if (auto &&nbd{nonBlockDo.Parse(state)}) {
1720+ processEpc(std::move(*nbd));
1721+ while (auto &&epc{attempt(executionPartConstruct).Parse(state)}) {
1722+ processEpc(std::move(*epc));
1723+ if (labels.empty()) {
1724+ break;
1725+ }
1726+ }
1727+ }
1728+
1729+ if (!body.empty()) {
1730+ return std::move(body);
1731+ }
1732+ return std::nullopt;
1733+ }
1734+
1735+ private:
1736+ // Is the template argument "Statement<T>" for some T?
1737+ template <typename T> struct IsStatement {
1738+ static constexpr bool value{false};
1739+ };
1740+ template <typename T> struct IsStatement<Statement<T>> {
1741+ static constexpr bool value{true};
1742+ };
1743+
1744+ // Get the Label from a Statement<...> contained in an ExecutionPartConstruct,
1745+ // or std::nullopt, if there is no Statement<...> contained in there.
1746+ template <typename T>
1747+ static std::optional<Label> GetStatementLabel(const T &stmt) {
1748+ if constexpr (IsStatement<T>::value) {
1749+ return stmt.label;
1750+ } else if constexpr (WrapperTrait<T>) {
1751+ return GetStatementLabel(stmt.v);
1752+ } else if constexpr (UnionTrait<T>) {
1753+ return common::visit(
1754+ [&](auto &&s) { return GetStatementLabel(s); }, stmt.u);
1755+ }
1756+ return std::nullopt;
1757+ }
1758+ };
1759+
1760+ struct LoopNestParser {
1761+ using resultType = Block;
1762+
1763+ std::optional<resultType> Parse(ParseState &state) const {
1764+ // Parse !$DIR as an ExecutionPartConstruct
1765+ auto fortranDirective{predicated(executionPartConstruct,
1766+ [](auto &epc) { return Unwrap<CompilerDirective>(epc); })};
1767+ // Parse DO loop as an ExecutionPartConstruct
1768+ auto fortranDoConstruct{predicated(executionPartConstruct,
1769+ [&](auto &epc) { return Unwrap<DoConstruct>(epc); })};
1770+ ParseState backtrack{state};
1771+
1772+ Block body;
1773+ llvm::move(*many(fortranDirective).Parse(state), std::back_inserter(body));
1774+
1775+ if (auto &&doLoop{attempt(fortranDoConstruct).Parse(state)}) {
1776+ body.push_back(std::move(*doLoop));
1777+ return std::move(body);
1778+ }
1779+ if (auto &&labelDo{attempt(NonBlockDoConstructParser{}).Parse(state)}) {
1780+ llvm::move(*labelDo, std::back_inserter(body));
1781+ return std::move(body);
1782+ }
1783+ if (auto &&sblock{attempt(StrictlyStructuredBlockParser{}).Parse(state)}) {
1784+ llvm::move(*sblock, std::back_inserter(body));
1785+ return std::move(body);
1786+ }
1787+ // If it's neither a DO-loop, nor a BLOCK, undo the parsing of the
1788+ // directives and fail.
1789+ state = backtrack;
1790+ return std::nullopt;
1791+ }
1792+ };
1793+
16591794TYPE_PARSER(construct<OmpErrorDirective>(
16601795 predicated(Parser<OmpDirectiveName>{},
16611796 IsDirective(llvm::omp::Directive::OMPD_error)) >=
@@ -1783,6 +1918,54 @@ struct OmpBlockConstructParser {
17831918 llvm::omp::Directive dir_;
17841919};
17851920
1921+ struct OmpLoopConstructParser {
1922+ using resultType = OpenMPLoopConstruct;
1923+
1924+ constexpr OmpLoopConstructParser(DirectiveSet dirs) : dirs_(dirs) {}
1925+
1926+ std::optional<resultType> Parse(ParseState &state) const {
1927+ auto ompLoopConstruct{asBlock(predicated(executionPartConstruct,
1928+ [](auto &epc) { return Unwrap<OpenMPLoopConstruct>(epc); }))};
1929+ auto loopItem{LoopNestParser{} || ompLoopConstruct};
1930+
1931+ if (auto &&begin{OmpBeginDirectiveParser(dirs_).Parse(state)}) {
1932+ auto loopDir{begin->DirName().v};
1933+ auto assoc{llvm::omp::getDirectiveAssociation(loopDir)};
1934+ if (assoc == llvm::omp::Association::LoopNest) {
1935+ if (auto &&item{attempt(loopItem).Parse(state)}) {
1936+ auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)};
1937+ return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)),
1938+ std::move(*item),
1939+ llvm::transformOptional(std::move(*end),
1940+ [](auto &&s) { return OmpEndLoopDirective(std::move(s)); })};
1941+ } else if (auto &&empty{pure<Block>().Parse(state)}) {
1942+ // Allow empty body.
1943+ auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)};
1944+ return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)),
1945+ std::move(*empty),
1946+ llvm::transformOptional(std::move(*end),
1947+ [](auto &&s) { return OmpEndLoopDirective(std::move(s)); })};
1948+ }
1949+ } else if (assoc == llvm::omp::Association::LoopSeq) {
1950+ // Parse loop sequence as a block.
1951+ if (auto &&body{block.Parse(state)}) {
1952+ auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)};
1953+ return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)),
1954+ std::move(*body),
1955+ llvm::transformOptional(std::move(*end),
1956+ [](auto &&s) { return OmpEndLoopDirective(std::move(s)); })};
1957+ }
1958+ } else {
1959+ llvm_unreachable("Unexpected association");
1960+ }
1961+ }
1962+ return std::nullopt;
1963+ }
1964+
1965+ private:
1966+ DirectiveSet dirs_;
1967+ };
1968+
17861969struct OmpDeclarativeAllocateParser {
17871970 using resultType = OmpAllocateDirective;
17881971
@@ -2267,13 +2450,7 @@ static constexpr DirectiveSet GetLoopDirectives() {
22672450 return loopDirectives;
22682451}
22692452
2270- TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>(
2271- sourced(OmpBeginDirectiveParser(GetLoopDirectives())))))
2272-
2273- // END OMP Loop directives
2274- TYPE_PARSER(sourced(construct<OmpEndLoopDirective>(
2275- sourced(OmpEndDirectiveParser(GetLoopDirectives())))))
2453+ TYPE_PARSER(sourced(construct<OpenMPLoopConstruct>(
2454+ OmpLoopConstructParser(GetLoopDirectives()))))
22762455
2277- TYPE_PARSER(construct<OpenMPLoopConstruct>(
2278- Parser<OmpBeginLoopDirective>{} / endOmpLine))
22792456} // namespace Fortran::parser
0 commit comments