diff options
Diffstat (limited to 'flang/lib/Parser/openmp-parsers.cpp')
-rw-r--r-- | flang/lib/Parser/openmp-parsers.cpp | 313 |
1 files changed, 215 insertions, 98 deletions
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index d349d8c..7daba33 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -34,6 +34,39 @@ namespace Fortran::parser { constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok; constexpr auto endOmpLine = space >> endOfLine; +// Given a parser for a single element, and a parser for a list of elements +// of the same type, create a parser that constructs the entire list by having +// the single element be the head of the list, and the rest be the tail. +template <typename ParserH, typename ParserT> struct ConsParser { + static_assert(std::is_same_v<std::list<typename ParserH::resultType>, + typename ParserT::resultType>); + + using resultType = typename ParserT::resultType; + constexpr ConsParser(ParserH h, ParserT t) : head_(h), tail_(t) {} + + std::optional<resultType> Parse(ParseState &state) const { + if (auto &&first{head_.Parse(state)}) { + if (auto rest{tail_.Parse(state)}) { + rest->push_front(std::move(*first)); + return std::move(*rest); + } + } + return std::nullopt; + } + +private: + const ParserH head_; + const ParserT tail_; +}; + +template <typename ParserH, typename ParserT, + typename ValueH = typename ParserH::resultType, + typename ValueT = typename ParserT::resultType, + typename = std::enable_if_t<std::is_same_v<std::list<ValueH>, ValueT>>> +constexpr auto cons(ParserH head, ParserT tail) { + return ConsParser<ParserH, ParserT>(head, tail); +} + // Given a parser P for a wrapper class, invoke P, and if it succeeds return // the wrapped object. template <typename Parser> struct UnwrapParser { @@ -449,6 +482,9 @@ TYPE_PARSER(construct<OmpAllocatorSimpleModifier>(scalarIntExpr)) TYPE_PARSER(construct<OmpAlwaysModifier>( // "ALWAYS" >> pure(OmpAlwaysModifier::Value::Always))) +TYPE_PARSER(construct<OmpAutomapModifier>( + "AUTOMAP" >> pure(OmpAutomapModifier::Value::Automap))) + TYPE_PARSER(construct<OmpChunkModifier>( // "SIMD" >> pure(OmpChunkModifier::Value::Simd))) @@ -466,6 +502,8 @@ TYPE_PARSER(construct<OmpDeviceModifier>( "ANCESTOR" >> pure(OmpDeviceModifier::Value::Ancestor) || "DEVICE_NUM" >> pure(OmpDeviceModifier::Value::Device_Num))) +TYPE_PARSER(construct<OmpDirectiveNameModifier>(OmpDirectiveNameParser{})) + TYPE_PARSER(construct<OmpExpectation>( // "PRESENT" >> pure(OmpExpectation::Value::Present))) @@ -601,6 +639,9 @@ TYPE_PARSER(sourced(construct<OmpDependClause::TaskDep::Modifier>(sourced( TYPE_PARSER( sourced(construct<OmpDeviceClause::Modifier>(Parser<OmpDeviceModifier>{}))) +TYPE_PARSER( + sourced(construct<OmpEnterClause::Modifier>(Parser<OmpAutomapModifier>{}))) + TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>( sourced(construct<OmpFromClause::Modifier>(Parser<OmpExpectation>{}) || construct<OmpFromClause::Modifier>(Parser<OmpMapper>{}) || @@ -609,7 +650,8 @@ TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>( TYPE_PARSER(sourced( construct<OmpGrainsizeClause::Modifier>(Parser<OmpPrescriptiveness>{}))) -TYPE_PARSER(sourced(construct<OmpIfClause::Modifier>(OmpDirectiveNameParser{}))) +TYPE_PARSER(sourced( + construct<OmpIfClause::Modifier>(Parser<OmpDirectiveNameModifier>{}))) TYPE_PARSER(sourced( construct<OmpInitClause::Modifier>( @@ -735,6 +777,10 @@ TYPE_PARSER(construct<OmpDefaultClause>( Parser<OmpDefaultClause::DataSharingAttribute>{}) || construct<OmpDefaultClause>(indirect(Parser<OmpDirectiveSpecification>{})))) +TYPE_PARSER(construct<OmpEnterClause>( + maybe(nonemptyList(Parser<OmpEnterClause::Modifier>{}) / ":"), + Parser<OmpObjectList>{})) + TYPE_PARSER(construct<OmpFailClause>( "ACQ_REL" >> pure(common::OmpMemoryOrderType::Acq_Rel) || "ACQUIRE" >> pure(common::OmpMemoryOrderType::Acquire) || @@ -1023,7 +1069,7 @@ TYPE_PARSER( // "DYNAMIC_ALLOCATORS" >> construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) || "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>( - parenthesized(Parser<OmpObjectList>{}))) || + parenthesized(Parser<OmpEnterClause>{}))) || "EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>( parenthesized(Parser<OmpObjectList>{}))) || "FAIL" >> construct<OmpClause>(construct<OmpClause::Fail>( @@ -1208,6 +1254,61 @@ TYPE_PARSER(sourced( maybe(Parser<OmpClauseList>{}), pure(OmpDirectiveSpecification::Flags::None)))) +static bool IsFortranBlockConstruct(const ExecutionPartConstruct &epc) { + // ExecutionPartConstruct -> ExecutableConstruct + // -> Indirection<BlockConstruct> + if (auto *ec{std::get_if<ExecutableConstruct>(&epc.u)}) { + return std::holds_alternative<common::Indirection<BlockConstruct>>(ec->u); + } else { + return false; + } +} + +struct StrictlyStructuredBlockParser { + using resultType = Block; + + std::optional<resultType> Parse(ParseState &state) const { + // Detect BLOCK construct without parsing the entire thing. + if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) { + if (auto epc{Parser<ExecutionPartConstruct>{}.Parse(state)}) { + if (IsFortranBlockConstruct(*epc)) { + Block block; + block.emplace_back(std::move(*epc)); + return std::move(block); + } + } + } + return std::nullopt; + } +}; + +struct LooselyStructuredBlockParser { + using resultType = Block; + + std::optional<resultType> Parse(ParseState &state) const { + // Detect BLOCK construct without parsing the entire thing. + if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) { + return std::nullopt; + } + Block body; + if (auto epc{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) { + if (!IsFortranBlockConstruct(*epc)) { + body.emplace_back(std::move(*epc)); + if (auto &&blk{attempt(block).Parse(state)}) { + for (auto &&s : *blk) { + body.emplace_back(std::move(s)); + } + } + } else { + // Fail if the first construct is BLOCK. + return std::nullopt; + } + } + // Empty body is ok. + return std::move(body); + } +}; + TYPE_PARSER(sourced(construct<OmpNothingDirective>("NOTHING" >> ok))) TYPE_PARSER(sourced(construct<OpenMPUtilityConstruct>( @@ -1280,16 +1381,41 @@ TYPE_PARSER(sourced(construct<OmpLoopDirective>(first( TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>( sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{}))) +static inline constexpr auto IsDirective(llvm::omp::Directive dir) { + return [dir](const OmpDirectiveName &name) -> bool { return dir == name.v; }; +} + +struct OmpBeginDirectiveParser { + using resultType = OmpDirectiveSpecification; + + constexpr OmpBeginDirectiveParser(llvm::omp::Directive dir) : dir_(dir) {} + + std::optional<resultType> Parse(ParseState &state) const { + auto &&p{predicated(Parser<OmpDirectiveName>{}, IsDirective(dir_)) >= + Parser<OmpDirectiveSpecification>{}}; + return p.Parse(state); + } + +private: + llvm::omp::Directive dir_; +}; + struct OmpEndDirectiveParser { using resultType = OmpDirectiveSpecification; constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) : dir_(dir) {} std::optional<resultType> Parse(ParseState &state) const { - if ((startOmpLine >> "END"_sptok).Parse(state)) { - auto &&dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)}; - if (dirSpec && dirSpec->DirId() == dir_) { - return std::move(dirSpec); + if (startOmpLine.Parse(state)) { + if (auto endToken{verbatim("END"_sptok).Parse(state)}) { + if (auto &&dirSpec{OmpBeginDirectiveParser(dir_).Parse(state)}) { + // Extend the "source" on both the OmpDirectiveName and the + // OmpDirectiveNameSpecification. + CharBlock &nameSource{std::get<OmpDirectiveName>(dirSpec->t).source}; + nameSource.ExtendToCover(endToken->source); + dirSpec->source.ExtendToCover(endToken->source); + return std::move(*dirSpec); + } } } return std::nullopt; @@ -1299,57 +1425,67 @@ private: llvm::omp::Directive dir_; }; -struct OmpAllocatorsConstructParser { - using resultType = OpenMPAllocatorsConstruct; +struct OmpStatementConstructParser { + using resultType = OmpBlockConstruct; + + constexpr OmpStatementConstructParser(llvm::omp::Directive dir) : dir_(dir) {} std::optional<resultType> Parse(ParseState &state) const { - auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)}; - if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_allocators) { - return std::nullopt; - } + if (auto begin{OmpBeginDirectiveParser(dir_).Parse(state)}) { + Block body; + if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) { + body.emplace_back(std::move(*stmt)); + } + // Allow empty block. Check for this in semantics. - // This should be an allocate-stmt. That will be checked in semantics. - Block block; - if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) { - block.emplace_back(std::move(*stmt)); + auto end{maybe(OmpEndDirectiveParser{dir_}).Parse(state)}; + return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)), + std::move(body), + llvm::transformOptional(std::move(*end), + [](auto &&s) { return OmpEndDirective(std::move(s)); })}; } - // Allow empty block. Check for this in semantics. - - auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_allocators}}; - return OpenMPAllocatorsConstruct{ - std::move(*dirSpec), std::move(block), *maybe(end).Parse(state)}; + return std::nullopt; } + +private: + llvm::omp::Directive dir_; }; -TYPE_PARSER(sourced( // - construct<OpenMPAllocatorsConstruct>( - "ALLOCATORS"_tok >= OmpAllocatorsConstructParser{}))) +struct OmpBlockConstructParser { + using resultType = OmpBlockConstruct; -struct OmpDispatchConstructParser { - using resultType = OpenMPDispatchConstruct; + constexpr OmpBlockConstructParser(llvm::omp::Directive dir) : dir_(dir) {} std::optional<resultType> Parse(ParseState &state) const { - auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)}; - if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_dispatch) { - return std::nullopt; - } - - // This should be a function call. That will be checked in semantics. - Block block; - if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) { - block.emplace_back(std::move(*stmt)); + if (auto &&begin{OmpBeginDirectiveParser(dir_).Parse(state)}) { + if (auto &&body{attempt(StrictlyStructuredBlockParser{}).Parse(state)}) { + // Try strictly-structured block with an optional end-directive + auto end{maybe(OmpEndDirectiveParser{dir_}).Parse(state)}; + return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)), + std::move(*body), + llvm::transformOptional(std::move(*end), + [](auto &&s) { return OmpEndDirective(std::move(s)); })}; + } else if (auto &&body{ + attempt(LooselyStructuredBlockParser{}).Parse(state)}) { + // Try loosely-structured block with a mandatory end-directive + if (auto end{OmpEndDirectiveParser{dir_}.Parse(state)}) { + return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)), + std::move(*body), OmpEndDirective{std::move(*end)}}; + } + } } - // Allow empty block. Check for this in semantics. - - auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_dispatch}}; - return OpenMPDispatchConstruct{ - std::move(*dirSpec), std::move(block), *maybe(end).Parse(state)}; + return std::nullopt; } + +private: + llvm::omp::Directive dir_; }; -TYPE_PARSER(sourced( // - construct<OpenMPDispatchConstruct>( - "DISPATCH"_tok >= OmpDispatchConstructParser{}))) +TYPE_PARSER(sourced(construct<OpenMPAllocatorsConstruct>( + OmpStatementConstructParser{llvm::omp::Directive::OMPD_allocators}))) + +TYPE_PARSER(sourced(construct<OpenMPDispatchConstruct>( + OmpStatementConstructParser{llvm::omp::Directive::OMPD_dispatch}))) // Parser for an arbitrary OpenMP ATOMIC construct. // @@ -1414,8 +1550,10 @@ struct OmpAtomicConstructParser { } } recursing_ = false; - return OpenMPAtomicConstruct{ - std::move(*dirSpec), std::move(tail.first), std::move(tail.second)}; + return OpenMPAtomicConstruct{OmpBeginDirective(std::move(*dirSpec)), + std::move(tail.first), + llvm::transformOptional(std::move(tail.second), + [](auto &&s) { return OmpEndDirective(std::move(s)); })}; } recursing_ = false; @@ -1516,10 +1654,6 @@ TYPE_PARSER(sourced( // predicated(OmpDirectiveNameParser{}, IsSimpleStandalone) >= Parser<OmpDirectiveSpecification>{}))) -static inline constexpr auto IsDirective(llvm::omp::Directive dir) { - return [dir](const OmpDirectiveName &name) -> bool { return dir == name.v; }; -} - TYPE_PARSER(sourced( // construct<OpenMPFlushConstruct>( predicated(OmpDirectiveNameParser{}, @@ -1570,36 +1704,6 @@ TYPE_PARSER( Parser<OpenMPInteropConstruct>{})) / endOfLine) -// Directives enclosing structured-block -TYPE_PARSER( - // In this context "TARGET UPDATE" can be parsed as a TARGET directive - // followed by an UPDATE clause. This is the only combination at the - // moment, exclude it explicitly. - (!("TARGET UPDATE"_sptok || "TARGET_UPDATE"_sptok)) >= - construct<OmpBlockDirective>(first( - "MASKED" >> pure(llvm::omp::Directive::OMPD_masked), - "MASTER" >> pure(llvm::omp::Directive::OMPD_master), - "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered), - "PARALLEL MASKED" >> pure(llvm::omp::Directive::OMPD_parallel_masked), - "PARALLEL MASTER" >> pure(llvm::omp::Directive::OMPD_parallel_master), - "PARALLEL WORKSHARE" >> - pure(llvm::omp::Directive::OMPD_parallel_workshare), - "PARALLEL" >> pure(llvm::omp::Directive::OMPD_parallel), - "SCOPE" >> pure(llvm::omp::Directive::OMPD_scope), - "SINGLE" >> pure(llvm::omp::Directive::OMPD_single), - "TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data), - "TARGET_DATA" >> pure(llvm::omp::Directive::OMPD_target_data), - "TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel), - "TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams), - "TARGET" >> pure(llvm::omp::Directive::OMPD_target), - "TASK"_id >> pure(llvm::omp::Directive::OMPD_task), - "TASKGROUP" >> pure(llvm::omp::Directive::OMPD_taskgroup), - "TEAMS" >> pure(llvm::omp::Directive::OMPD_teams), - "WORKSHARE" >> pure(llvm::omp::Directive::OMPD_workshare)))) - -TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>( - sourced(Parser<OmpBlockDirective>{}), Parser<OmpClauseList>{}))) - TYPE_PARSER(construct<OmpInitializerProc>(Parser<ProcedureDesignator>{}, parenthesized(many(maybe(","_tok) >> Parser<ActualArgSpec>{})))) @@ -1749,9 +1853,27 @@ TYPE_PARSER(sourced( block, maybe(Parser<OmpEndAssumeDirective>{} / endOmpLine)))) // Block Construct -TYPE_PARSER(construct<OpenMPBlockConstruct>( - Parser<OmpBeginBlockDirective>{} / endOmpLine, block, - Parser<OmpEndBlockDirective>{} / endOmpLine)) +#define MakeBlockConstruct(dir) \ + construct<OpenMPBlockConstruct>(OmpBlockConstructParser{dir}) +TYPE_PARSER( // + MakeBlockConstruct(llvm::omp::Directive::OMPD_masked) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_master) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_ordered) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel_masked) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel_master) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel_workshare) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_parallel) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_scope) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_single) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_target_data) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_target_parallel) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_target_teams) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_target) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_task) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_taskgroup) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_teams) || + MakeBlockConstruct(llvm::omp::Directive::OMPD_workshare)) +#undef MakeBlockConstruct // OMP SECTIONS Directive TYPE_PARSER(construct<OmpSectionsDirective>(first( @@ -1766,19 +1888,20 @@ TYPE_PARSER( sourced("END"_tok >> Parser<OmpSectionsDirective>{}), Parser<OmpClauseList>{}))) -// OMP SECTION-BLOCK - -TYPE_PARSER(construct<OpenMPSectionConstruct>(block)) - -TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >> - construct<OmpSectionBlocks>(nonemptySeparated( - construct<OpenMPConstruct>(sourced(Parser<OpenMPSectionConstruct>{})), - startOmpLine >> "SECTION"_tok / endOmpLine))) +static constexpr auto sectionDir{ + startOmpLine >> (predicated(OmpDirectiveNameParser{}, + IsDirective(llvm::omp::Directive::OMPD_section)) >= + Parser<OmpDirectiveSpecification>{})}; // OMP SECTIONS (OpenMP 5.0 - 2.8.1), PARALLEL SECTIONS (OpenMP 5.0 - 2.13.3) -TYPE_PARSER(construct<OpenMPSectionsConstruct>( +TYPE_PARSER(sourced(construct<OpenMPSectionsConstruct>( Parser<OmpBeginSectionsDirective>{} / endOmpLine, - Parser<OmpSectionBlocks>{}, Parser<OmpEndSectionsDirective>{} / endOmpLine)) + cons( // + construct<OpenMPConstruct>(sourced( + construct<OpenMPSectionConstruct>(maybe(sectionDir), block))), + many(construct<OpenMPConstruct>( + sourced(construct<OpenMPSectionConstruct>(sectionDir, block))))), + Parser<OmpEndSectionsDirective>{} / endOmpLine))) static bool IsExecutionPart(const OmpDirectiveName &name) { return name.IsExecutionPart(); @@ -1805,12 +1928,6 @@ TYPE_CONTEXT_PARSER("OpenMP construct"_en_US, construct<OpenMPConstruct>(Parser<OpenMPAssumeConstruct>{}), construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{})))) -// END OMP Block directives -TYPE_PARSER( - startOmpLine >> sourced(construct<OmpEndBlockDirective>( - sourced("END"_tok >> Parser<OmpBlockDirective>{}), - Parser<OmpClauseList>{}))) - // END OMP Loop directives TYPE_PARSER( startOmpLine >> sourced(construct<OmpEndLoopDirective>( |