//===-- lib/Parser/openmp-parsers.cpp -------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // Top-level grammar specification for OpenMP. // See OpenMP-4.5-grammar.txt for documentation. #include "basic-parsers.h" #include "expr-parsers.h" #include "misc-parsers.h" #include "stmt-parser.h" #include "token-parsers.h" #include "type-parser-implementation.h" #include "flang/Parser/parse-tree.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Frontend/OpenMP/OMP.h" // OpenMP Directives and Clauses namespace Fortran::parser { constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok; constexpr auto endOmpLine = space >> endOfLine; /// Parse OpenMP directive name (this includes compound directives). struct OmpDirectiveNameParser { using resultType = llvm::omp::Directive; using Token = TokenStringMatch; std::optional Parse(ParseState &state) const { for (const NameWithId &nid : directives()) { if (attempt(Token(nid.first.data())).Parse(state)) { return nid.second; } } return std::nullopt; } private: using NameWithId = std::pair; llvm::iterator_range directives() const; void initTokens(NameWithId *) const; }; llvm::iterator_range OmpDirectiveNameParser::directives() const { static NameWithId table[llvm::omp::Directive_enumSize]; [[maybe_unused]] static bool init = (initTokens(table), true); return llvm::make_range(std::cbegin(table), std::cend(table)); } void OmpDirectiveNameParser::initTokens(NameWithId *table) const { for (size_t i{0}, e{llvm::omp::Directive_enumSize}; i != e; ++i) { auto id{static_cast(i)}; llvm::StringRef name{llvm::omp::getOpenMPDirectiveName(id)}; table[i] = std::make_pair(name.str(), id); } // Sort the table with respect to the directive name length in a descending // order. This is to make sure that longer names are tried first, before // any potential prefix (e.g. "target update" before "target"). std::sort(table, table + llvm::omp::Directive_enumSize, [](auto &a, auto &b) { return a.first.size() > b.first.size(); }); } template struct ModifierList { constexpr ModifierList(Separator sep) : sep_(sep) {} constexpr ModifierList(const ModifierList &) = default; constexpr ModifierList(ModifierList &&) = default; using resultType = std::list; std::optional Parse(ParseState &state) const { auto listp{nonemptySeparated(Parser{}, sep_)}; if (auto result{attempt(listp).Parse(state)}) { if (!attempt(":"_tok).Parse(state)) { return std::nullopt; } return std::move(result); } return resultType{}; } private: const Separator sep_; }; // Use a function to create ModifierList because functions allow "partial" // template argument deduction: "modifierList(sep)" would be legal, // while "ModifierList(sep)" would complain about a missing template // argument "Separator". template constexpr ModifierList modifierList(Separator sep) { return ModifierList(sep); } // Parse the input as any modifier from ClauseTy, but only succeed if // the result was the SpecificTy. It requires that SpecificTy is one // of the alternatives in ClauseTy::Modifier. // The reason to have this is that ClauseTy::Modifier has "source", // while specific modifiers don't. This class allows to parse a specific // modifier together with obtaining its location. template struct SpecificModifierParser { using resultType = typename ClauseTy::Modifier; std::optional Parse(ParseState &state) const { if (auto result{attempt(Parser{}).Parse(state)}) { if (std::holds_alternative(result->u)) { return result; } } return std::nullopt; } }; // OpenMP Clauses // [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple | // identifier = subscript-triple // [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not // specified then the type of that iterator is default integer. // [5.0:49:14] The iterator-type must be an integer type. static std::list makeEntityList(std::list &&names) { std::list entities; for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) { EntityDecl entityDecl( /*ObjectName=*/std::move(*iter), std::optional{}, std::optional{}, std::optional{}, std::optional{}); entities.push_back(std::move(entityDecl)); } return entities; } static TypeDeclarationStmt makeIterSpecDecl( DeclarationTypeSpec &&spec, std::list &&names) { return TypeDeclarationStmt( std::move(spec), std::list{}, makeEntityList(std::move(names))); } static TypeDeclarationStmt makeIterSpecDecl(std::list &&names) { // Assume INTEGER without kind selector. DeclarationTypeSpec typeSpec( IntrinsicTypeSpec{IntegerTypeSpec{std::nullopt}}); return TypeDeclarationStmt(std::move(typeSpec), std::list{}, makeEntityList(std::move(names))); } TYPE_PARSER(sourced(construct( OmpDirectiveNameParser{}, maybe(indirect(Parser{}))))) // --- Parsers for context traits ------------------------------------- static std::string nameToString(Name &&name) { return name.ToString(); } TYPE_PARSER(sourced(construct( // construct(space >> charLiteralConstantWithoutKind) || construct( applyFunction(nameToString, Parser{}))))) TYPE_PARSER(sourced(construct( // "SCORE"_id >> parenthesized(scalarIntExpr)))) TYPE_PARSER(sourced(construct( Parser{}, parenthesized(nonemptySeparated( indirect(Parser{}), ","))))) TYPE_PARSER(sourced(construct( construct( Parser{}) || construct(Parser{}) || construct(scalarExpr)))) TYPE_PARSER(construct( "ARCH"_id >> pure(OmpTraitSelectorName::Value::Arch) || "ATOMIC_DEFAULT_MEM_ORDER"_id >> pure(OmpTraitSelectorName::Value::Atomic_Default_Mem_Order) || "CONDITION"_id >> pure(OmpTraitSelectorName::Value::Condition) || "DEVICE_NUM"_id >> pure(OmpTraitSelectorName::Value::Device_Num) || "EXTENSION"_id >> pure(OmpTraitSelectorName::Value::Extension) || "ISA"_id >> pure(OmpTraitSelectorName::Value::Isa) || "KIND"_id >> pure(OmpTraitSelectorName::Value::Kind) || "REQUIRES"_id >> pure(OmpTraitSelectorName::Value::Requires) || "SIMD"_id >> pure(OmpTraitSelectorName::Value::Simd) || "UID"_id >> pure(OmpTraitSelectorName::Value::Uid) || "VENDOR"_id >> pure(OmpTraitSelectorName::Value::Vendor))) TYPE_PARSER(sourced(construct( // Parse predefined names first (because of SIMD). construct(Parser{}) || construct(OmpDirectiveNameParser{}) || // identifier-or-string for extensions construct( applyFunction(nameToString, Parser{})) || construct(space >> charLiteralConstantWithoutKind)))) // Parser for OmpTraitSelector::Properties template static constexpr auto propertyListParser(PropParser... pp) { // Parse the property list "(score(expr): item1...)" in three steps: // 1. Parse the "(" // 2. Parse the optional "score(expr):" // 3. Parse the "item1, ...)", together with the ")". // The reason for including the ")" in the 3rd step is to force parsing // the entire list in each of the alternative property parsers. Otherwise, // the name parser could stop after "foo" in "(foo, bar(1))", without // allowing the next parser to give the list a try. auto listOf{[](auto parser) { // return nonemptySeparated(parser, ","); }}; using P = OmpTraitProperty; return maybe("(" >> // construct( maybe(Parser{} / ":"), (attempt(listOf(sourced(construct

(pp))) / ")") || ...))); } // Parser for OmpTraitSelector struct TraitSelectorParser { using resultType = OmpTraitSelector; constexpr TraitSelectorParser(Parser p) : np(p) {} std::optional Parse(ParseState &state) const { auto name{attempt(np).Parse(state)}; if (!name.has_value()) { return std::nullopt; } // Default fallback parser for lists that cannot be parser using the // primary property parser. auto extParser{Parser{}}; if (auto *v{std::get_if(&name->u)}) { // (*) The comments below show the sections of the OpenMP spec that // describe given trait. The cases marked with a (*) are those where // the spec doesn't assign any list-type to these traits, but for // convenience they can be treated as if they were. switch (*v) { // name-list properties case OmpTraitSelectorName::Value::Arch: // [6.0:319:18] case OmpTraitSelectorName::Value::Extension: // [6.0:319:30] case OmpTraitSelectorName::Value::Isa: // [6.0:319:15] case OmpTraitSelectorName::Value::Kind: // [6.0:319:10] case OmpTraitSelectorName::Value::Uid: // [6.0:319:23](*) case OmpTraitSelectorName::Value::Vendor: { // [6.0:319:27] auto pp{propertyListParser(Parser{}, extParser)}; return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); } // clause-list case OmpTraitSelectorName::Value::Atomic_Default_Mem_Order: // [6.0:321:26-29](*) case OmpTraitSelectorName::Value::Requires: // [6.0:319:33] case OmpTraitSelectorName::Value::Simd: { // [6.0:318:31] auto pp{propertyListParser(indirect(Parser{}), extParser)}; return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); } // expr-list case OmpTraitSelectorName::Value::Condition: // [6.0:321:33](*) case OmpTraitSelectorName::Value::Device_Num: { // [6.0:321:23-24](*) auto pp{propertyListParser(scalarExpr, extParser)}; return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); } } // switch } else { // The other alternatives are `llvm::omp::Directive`, and `std::string`. // The former doesn't take any properties[1], the latter is a name of an // extension[2]. // [1] [6.0:319:1-2] // [2] [6.0:319:36-37] auto pp{propertyListParser(extParser)}; return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); } llvm_unreachable("Unhandled trait name?"); } private: const Parser np; }; TYPE_PARSER(sourced(construct( sourced(TraitSelectorParser(Parser{}))))) TYPE_PARSER(construct( "CONSTRUCT"_id >> pure(OmpTraitSetSelectorName::Value::Construct) || "DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Device) || "IMPLEMENTATION"_id >> pure(OmpTraitSetSelectorName::Value::Implementation) || "TARGET_DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Target_Device) || "USER"_id >> pure(OmpTraitSetSelectorName::Value::User))) TYPE_PARSER(sourced(construct( Parser{}))) TYPE_PARSER(sourced(construct( // Parser{}, "=" >> braced(nonemptySeparated(Parser{}, ","))))) TYPE_PARSER(sourced(construct( nonemptySeparated(Parser{}, ",")))) // Parser == Parser // --- Parsers for clause modifiers ----------------------------------- TYPE_PARSER(construct(scalarIntExpr)) TYPE_PARSER(construct( // "ALIGN" >> parenthesized(scalarIntExpr))) TYPE_PARSER(construct( "ALLOCATOR" >> parenthesized(scalarIntExpr))) TYPE_PARSER(construct(scalarIntExpr)) TYPE_PARSER(construct( // "SIMD" >> pure(OmpChunkModifier::Value::Simd))) TYPE_PARSER(construct( "SINK" >> pure(OmpDependenceType::Value::Sink) || "SOURCE" >> pure(OmpDependenceType::Value::Source))) TYPE_PARSER(construct( "ANCESTOR" >> pure(OmpDeviceModifier::Value::Ancestor) || "DEVICE_NUM" >> pure(OmpDeviceModifier::Value::Device_Num))) TYPE_PARSER(construct( // "PRESENT" >> pure(OmpExpectation::Value::Present))) TYPE_PARSER(construct( // Using Parser or Parser has the problem // that they will attempt to treat what follows the '=' as initialization. // There are several issues with that, // 1. integer :: i = 0:10 will be parsed as "integer :: i = 0", followed // by triplet ":10". // 2. integer :: j = i:10 will be flagged as an error because the // initializer 'i' must be constant (in declarations). In an iterator // specifier the 'j' is not an initializer and can be a variable. (applyFunction(makeIterSpecDecl, Parser{} / maybe("::"_tok), nonemptyList(Parser{}) / "="_tok) || applyFunction( makeIterSpecDecl, nonemptyList(Parser{}) / "="_tok)), subscriptTriplet)) // [5.0] 2.1.6 iterator -> iterator-specifier-list TYPE_PARSER(construct( // "ITERATOR" >> parenthesized(nonemptyList(sourced(Parser{}))))) TYPE_PARSER(construct( "CONDITIONAL" >> pure(OmpLastprivateModifier::Value::Conditional))) // 2.15.3.7 LINEAR (linear-list: linear-step) // linear-list -> list | modifier(list) // linear-modifier -> REF | VAL | UVAL TYPE_PARSER(construct( // "REF" >> pure(OmpLinearModifier::Value::Ref) || "VAL" >> pure(OmpLinearModifier::Value::Val) || "UVAL" >> pure(OmpLinearModifier::Value::Uval))) TYPE_PARSER(construct( // "MAPPER"_tok >> parenthesized(Parser{}))) // map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM TYPE_PARSER(construct( // "ALLOC" >> pure(OmpMapType::Value::Alloc) || "DELETE" >> pure(OmpMapType::Value::Delete) || "FROM" >> pure(OmpMapType::Value::From) || "RELEASE" >> pure(OmpMapType::Value::Release) || "TO"_id >> pure(OmpMapType::Value::To) || "TOFROM" >> pure(OmpMapType::Value::Tofrom))) // map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT TYPE_PARSER(construct( "ALWAYS" >> pure(OmpMapTypeModifier::Value::Always) || "CLOSE" >> pure(OmpMapTypeModifier::Value::Close) || "OMPX_HOLD" >> pure(OmpMapTypeModifier::Value::Ompx_Hold) || "PRESENT" >> pure(OmpMapTypeModifier::Value::Present))) // 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list) TYPE_PARSER(construct(Parser{}) || construct(Parser{})) TYPE_PARSER(construct( "REPRODUCIBLE" >> pure(OmpOrderModifier::Value::Reproducible) || "UNCONSTRAINED" >> pure(OmpOrderModifier::Value::Unconstrained))) TYPE_PARSER(construct( "MONOTONIC" >> pure(OmpOrderingModifier::Value::Monotonic) || "NONMONOTONIC" >> pure(OmpOrderingModifier::Value::Nonmonotonic) || "SIMD" >> pure(OmpOrderingModifier::Value::Simd))) TYPE_PARSER(construct( "STRICT" >> pure(OmpPrescriptiveness::Value::Strict))) TYPE_PARSER(construct( "INSCAN" >> pure(OmpReductionModifier::Value::Inscan) || "TASK" >> pure(OmpReductionModifier::Value::Task) || "DEFAULT" >> pure(OmpReductionModifier::Value::Default))) TYPE_PARSER(construct( // "STEP" >> parenthesized(scalarIntExpr))) TYPE_PARSER(construct(scalarIntExpr)) TYPE_PARSER(construct( "DEPOBJ" >> pure(OmpTaskDependenceType::Value::Depobj) || "IN"_id >> pure(OmpTaskDependenceType::Value::In) || "INOUT"_id >> pure(OmpTaskDependenceType::Value::Inout) || "INOUTSET"_id >> pure(OmpTaskDependenceType::Value::Inoutset) || "MUTEXINOUTSET" >> pure(OmpTaskDependenceType::Value::Mutexinoutset) || "OUT" >> pure(OmpTaskDependenceType::Value::Out))) TYPE_PARSER(construct( "AGGREGATE" >> pure(OmpVariableCategory::Value::Aggregate) || "ALL"_id >> pure(OmpVariableCategory::Value::All) || "ALLOCATABLE" >> pure(OmpVariableCategory::Value::Allocatable) || "POINTER" >> pure(OmpVariableCategory::Value::Pointer) || "SCALAR" >> pure(OmpVariableCategory::Value::Scalar))) // This could be auto-generated. TYPE_PARSER( sourced(construct(Parser{}))) TYPE_PARSER( sourced(construct(Parser{}))) TYPE_PARSER(sourced(construct(sourced( construct(Parser{}) || construct( Parser{}) || construct( Parser{}))))) TYPE_PARSER(sourced( construct(Parser{}))) TYPE_PARSER(sourced(construct(sourced( construct(Parser{}) || construct( Parser{}))))) TYPE_PARSER( sourced(construct(Parser{}))) TYPE_PARSER(sourced(construct( sourced(construct(Parser{}) || construct(Parser{}) || construct(Parser{}))))) TYPE_PARSER(sourced( construct(Parser{}))) TYPE_PARSER(sourced(construct(OmpDirectiveNameParser{}))) TYPE_PARSER(sourced(construct( Parser{}))) TYPE_PARSER(sourced(construct( Parser{}))) TYPE_PARSER(sourced( construct(Parser{}) || construct(Parser{}) || construct(Parser{}))) TYPE_PARSER(sourced(construct( sourced(construct(Parser{}) || construct(Parser{}) || construct(Parser{}) || construct(Parser{}))))) TYPE_PARSER( sourced(construct(Parser{}))) TYPE_PARSER(sourced( construct(Parser{}))) TYPE_PARSER(sourced(construct(sourced( construct(Parser{}) || construct( Parser{}))))) TYPE_PARSER(sourced(construct(sourced( construct(Parser{}) || construct(Parser{}))))) TYPE_PARSER(sourced(construct( Parser{}))) TYPE_PARSER(sourced(construct( sourced(construct(Parser{}) || construct(Parser{}) || construct(Parser{}))))) TYPE_PARSER(sourced(construct( // Parser{}))) // --- Parsers for clauses -------------------------------------------- /// `MOBClause` is a clause that has a /// std::tuple. /// Helper function to create a typical modifiers-objects clause, where the /// commas separating individual modifiers are optional, and the clause /// contains a bool member to indicate whether it was fully comma-separated /// or not. template static inline MOBClause makeMobClause( std::list &&mods, OmpObjectList &&objs) { if (!mods.empty()) { return MOBClause{std::move(mods), std::move(objs), CommaSeparated}; } else { using ListTy = std::list; return MOBClause{std::optional{}, std::move(objs), CommaSeparated}; } } // [5.0] 2.10.1 affinity([aff-modifier:] locator-list) // aff-modifier: interator-modifier TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), Parser{})) // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) TYPE_PARSER(construct( "PRIVATE" >> pure(OmpDefaultClause::DataSharingAttribute::Private) || "FIRSTPRIVATE" >> pure(OmpDefaultClause::DataSharingAttribute::Firstprivate) || "SHARED" >> pure(OmpDefaultClause::DataSharingAttribute::Shared) || "NONE" >> pure(OmpDefaultClause::DataSharingAttribute::None))) TYPE_PARSER(construct( construct( Parser{}) || construct(Parser{}))) // 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD) TYPE_PARSER(construct( "CLOSE" >> pure(OmpProcBindClause::AffinityPolicy::Close) || "MASTER" >> pure(OmpProcBindClause::AffinityPolicy::Master) || "PRIMARY" >> pure(OmpProcBindClause::AffinityPolicy::Primary) || "SPREAD" >> pure(OmpProcBindClause::AffinityPolicy::Spread))) TYPE_PARSER(construct( applyFunction(makeMobClause, modifierList(","_tok), Parser{}) || applyFunction(makeMobClause, modifierList(maybe(","_tok)), Parser{}))) // [OpenMP 5.0] // 2.19.7.2 defaultmap(implicit-behavior[:variable-category]) // implicit-behavior -> ALLOC | TO | FROM | TOFROM | FIRSRTPRIVATE | NONE | // DEFAULT // variable-category -> ALL | SCALAR | AGGREGATE | ALLOCATABLE | POINTER TYPE_PARSER(construct( construct( "ALLOC" >> pure(OmpDefaultmapClause::ImplicitBehavior::Alloc) || "TO"_id >> pure(OmpDefaultmapClause::ImplicitBehavior::To) || "FROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::From) || "TOFROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::Tofrom) || "FIRSTPRIVATE" >> pure(OmpDefaultmapClause::ImplicitBehavior::Firstprivate) || "NONE" >> pure(OmpDefaultmapClause::ImplicitBehavior::None) || "DEFAULT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Default)), maybe(":" >> nonemptyList(Parser{})))) TYPE_PARSER(construct( "STATIC" >> pure(OmpScheduleClause::Kind::Static) || "DYNAMIC" >> pure(OmpScheduleClause::Kind::Dynamic) || "GUIDED" >> pure(OmpScheduleClause::Kind::Guided) || "AUTO" >> pure(OmpScheduleClause::Kind::Auto) || "RUNTIME" >> pure(OmpScheduleClause::Kind::Runtime))) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), Parser{}, maybe("," >> scalarIntExpr))) // device([ device-modifier :] scalar-integer-expression) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), scalarIntExpr)) // device_type(any | host | nohost) TYPE_PARSER(construct( "ANY" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Any) || "HOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Host) || "NOHOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Nohost))) // 2.12 IF (directive-name-modifier: scalar-logical-expr) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), scalarLogicalExpr)) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), Parser{})) // OMP 5.0 2.19.5.6 IN_REDUCTION (reduction-identifier: variable-name-list) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), Parser{})) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), Parser{})) // OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list) // OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier // [, allocate-modifier] :] // variable-name-list) // allocate-modifier -> allocator | align TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), Parser{})) // iteration-offset -> +/- non-negative-constant-expr TYPE_PARSER(construct( Parser{}, scalarIntConstantExpr)) // iteration -> iteration-variable [+/- nonnegative-scalar-integer-constant] TYPE_PARSER(construct(name, maybe(Parser{}))) TYPE_PARSER(construct(nonemptyList(Parser{}))) TYPE_PARSER(construct( construct(construct( "SINK"_tok >> ":"_tok >> Parser{})) || construct(construct("SOURCE"_tok)))) TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, construct( // Try to parse OmpDoacross first, because TaskDep will succeed on // "sink: xxx", interpreting it to not have any modifiers, and "sink" // being an OmpObject. Parsing of the TaskDep variant will stop right // after the "sink", leaving the ": xxx" unvisited. construct(Parser{}) || // Parse TaskDep after Doacross. construct(construct( maybe(nonemptyList(Parser{}) / ": "), Parser{})))) TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US, construct(Parser{})) TYPE_PARSER(construct( applyFunction(makeMobClause, modifierList(","_tok), Parser{}) || applyFunction(makeMobClause, modifierList(maybe(","_tok)), Parser{}))) TYPE_PARSER(construct( applyFunction(makeMobClause, modifierList(","_tok), Parser{}) || applyFunction(makeMobClause, modifierList(maybe(","_tok)), Parser{}))) OmpLinearClause makeLinearFromOldSyntax(OmpLinearClause::Modifier &&lm, OmpObjectList &&objs, std::optional &&ssm) { std::list mods; mods.emplace_back(std::move(lm)); if (ssm) { mods.emplace_back(std::move(*ssm)); } return OmpLinearClause{std::move(objs), mods.empty() ? decltype(mods){} : std::move(mods), /*PostModified=*/false}; } TYPE_PARSER( // Parse the "modifier(x)" first, because syntacticaly it will match // an array element (i.e. a list item). // LINEAR(linear-modifier(list) [: step-simple-modifier]) construct( // applyFunction(makeLinearFromOldSyntax, SpecificModifierParser{}, parenthesized(Parser{}), maybe(":"_tok >> SpecificModifierParser{}))) || // LINEAR(list [: modifiers]) construct( // Parser{}, maybe(":"_tok >> nonemptyList(Parser{})), /*PostModified=*/pure(true))) // OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle) TYPE_PARSER(construct(Parser{})) // 2.8.1 ALIGNED (list: alignment) TYPE_PARSER(construct(Parser{}, maybe(":" >> nonemptyList(Parser{})))) TYPE_PARSER(construct( construct(Parser{}) || construct(Parser{}))) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), "CONCURRENT" >> pure(OmpOrderClause::Ordering::Concurrent))) TYPE_PARSER(construct( Parser{})) TYPE_PARSER(construct( maybe(sourced(Parser{})))) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), maybe(sourced(Parser{})))) // OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), scalarIntExpr)) // OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), scalarIntExpr)) TYPE_PARSER( construct(designator) || construct("/" >> name / "/")) // OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list) TYPE_PARSER(construct( maybe(nonemptyList(Parser{}) / ":"), Parser{})) // OMP 5.2 11.7.1 BIND ( PARALLEL | TEAMS | THREAD ) TYPE_PARSER(construct( "PARALLEL" >> pure(OmpBindClause::Binding::Parallel) || "TEAMS" >> pure(OmpBindClause::Binding::Teams) || "THREAD" >> pure(OmpBindClause::Binding::Thread))) TYPE_PARSER(construct(scalarIntExpr)) TYPE_PARSER(construct( "EXECUTION" >> pure(OmpAtClause::ActionTime::Execution) || "COMPILATION" >> pure(OmpAtClause::ActionTime::Compilation))) TYPE_PARSER(construct( "FATAL" >> pure(OmpSeverityClause::Severity::Fatal) || "WARNING" >> pure(OmpSeverityClause::Severity::Warning))) TYPE_PARSER(construct(expr)) TYPE_PARSER( "ACQUIRE" >> construct(construct()) || "ACQ_REL" >> construct(construct()) || "AFFINITY" >> construct(construct( parenthesized(Parser{}))) || "ALIGN" >> construct(construct( parenthesized(Parser{}))) || "ALIGNED" >> construct(construct( parenthesized(Parser{}))) || "ALLOCATE" >> construct(construct( parenthesized(Parser{}))) || "ALLOCATOR" >> construct(construct( parenthesized(scalarIntExpr))) || "AT" >> construct(construct( parenthesized(Parser{}))) || "ATOMIC_DEFAULT_MEM_ORDER" >> construct(construct( parenthesized(Parser{}))) || "BIND" >> construct(construct( parenthesized(Parser{}))) || "COLLAPSE" >> construct(construct( parenthesized(scalarIntConstantExpr))) || "COPYIN" >> construct(construct( parenthesized(Parser{}))) || "COPYPRIVATE" >> construct(construct( (parenthesized(Parser{})))) || "DEFAULT"_id >> construct(construct( parenthesized(Parser{}))) || "DEFAULTMAP" >> construct(construct( parenthesized(Parser{}))) || "DEPEND" >> construct(construct( parenthesized(Parser{}))) || "DESTROY" >> construct(construct(maybe(parenthesized( construct(Parser{}))))) || "DEVICE" >> construct(construct( parenthesized(Parser{}))) || "DEVICE_TYPE" >> construct(construct( parenthesized(Parser{}))) || "DIST_SCHEDULE" >> construct(construct( parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) || "DOACROSS" >> construct(parenthesized(Parser{})) || "DYNAMIC_ALLOCATORS" >> construct(construct()) || "ENTER" >> construct(construct( parenthesized(Parser{}))) || "EXCLUSIVE" >> construct(construct( parenthesized(Parser{}))) || "FILTER" >> construct(construct( parenthesized(scalarIntExpr))) || "FINAL" >> construct(construct( parenthesized(scalarLogicalExpr))) || "FIRSTPRIVATE" >> construct(construct( parenthesized(Parser{}))) || "FROM" >> construct(construct( parenthesized(Parser{}))) || "FULL" >> construct(construct()) || "GRAINSIZE" >> construct(construct( parenthesized(Parser{}))) || "HAS_DEVICE_ADDR" >> construct(construct( parenthesized(Parser{}))) || "HINT" >> construct( construct(parenthesized(constantExpr))) || "IF" >> construct(construct( parenthesized(Parser{}))) || "INBRANCH" >> construct(construct()) || "INCLUSIVE" >> construct(construct( parenthesized(Parser{}))) || "IS_DEVICE_PTR" >> construct(construct( parenthesized(Parser{}))) || "LASTPRIVATE" >> construct(construct( parenthesized(Parser{}))) || "LINEAR" >> construct(construct( parenthesized(Parser{}))) || "LINK" >> construct(construct( parenthesized(Parser{}))) || "MAP" >> construct(construct( parenthesized(Parser{}))) || "MATCH" >> construct(construct( parenthesized(Parser{}))) || "MERGEABLE" >> construct(construct()) || "MESSAGE" >> construct(construct( parenthesized(Parser{}))) || "NOCONTEXT" >> construct(construct( parenthesized(scalarLogicalExpr))) || "NOGROUP" >> construct(construct()) || "NONTEMPORAL" >> construct(construct( parenthesized(nonemptyList(name)))) || "NOTINBRANCH" >> construct(construct()) || "NOVARIANTS" >> construct(construct( parenthesized(scalarLogicalExpr))) || "NOWAIT" >> construct(construct()) || "NUM_TASKS" >> construct(construct( parenthesized(Parser{}))) || "NUM_TEAMS" >> construct(construct( parenthesized(scalarIntExpr))) || "NUM_THREADS" >> construct(construct( parenthesized(scalarIntExpr))) || "OMPX_BARE" >> construct(construct()) || "ORDER" >> construct(construct( parenthesized(Parser{}))) || "ORDERED" >> construct(construct( maybe(parenthesized(scalarIntConstantExpr)))) || "OTHERWISE" >> construct(construct( maybe(parenthesized(Parser{})))) || "PARTIAL" >> construct(construct( maybe(parenthesized(scalarIntConstantExpr)))) || "PRIORITY" >> construct(construct( parenthesized(scalarIntExpr))) || "PRIVATE" >> construct(construct( parenthesized(Parser{}))) || "PROC_BIND" >> construct(construct( parenthesized(Parser{}))) || "REDUCTION"_id >> construct(construct( parenthesized(Parser{}))) || "IN_REDUCTION" >> construct(construct( parenthesized(Parser{}))) || "DETACH" >> construct(construct( parenthesized(Parser{}))) || "TASK_REDUCTION" >> construct(construct( parenthesized(Parser{}))) || "RELAXED" >> construct(construct()) || "RELEASE" >> construct(construct()) || "REVERSE_OFFLOAD" >> construct(construct()) || "SAFELEN" >> construct(construct( parenthesized(scalarIntConstantExpr))) || "SCHEDULE" >> construct(construct( parenthesized(Parser{}))) || "SEQ_CST" >> construct(construct()) || "SEVERITY" >> construct(construct( parenthesized(Parser{}))) || "SHARED" >> construct(construct( parenthesized(Parser{}))) || "SIMD"_id >> construct(construct()) || "SIMDLEN" >> construct(construct( parenthesized(scalarIntConstantExpr))) || "SIZES" >> construct(construct( parenthesized(nonemptyList(scalarIntExpr)))) || "PERMUTATION" >> construct(construct( parenthesized(nonemptyList(scalarIntExpr)))) || "THREADS" >> construct(construct()) || "THREAD_LIMIT" >> construct(construct( parenthesized(scalarIntExpr))) || "TO" >> construct(construct( parenthesized(Parser{}))) || "USE_DEVICE_PTR" >> construct(construct( parenthesized(Parser{}))) || "USE_DEVICE_ADDR" >> construct(construct( parenthesized(Parser{}))) || "UNIFIED_ADDRESS" >> construct(construct()) || "UNIFIED_SHARED_MEMORY" >> construct(construct()) || "UNIFORM" >> construct(construct( parenthesized(nonemptyList(name)))) || "UNTIED" >> construct(construct()) || "UPDATE" >> construct(construct( parenthesized(Parser{}))) || "WHEN" >> construct(construct( parenthesized(Parser{})))) // [Clause, [Clause], ...] TYPE_PARSER(sourced(construct( many(maybe(","_tok) >> sourced(Parser{}))))) // 2.1 (variable | /common-block/ | array-sections) TYPE_PARSER(construct(nonemptyList(Parser{}))) TYPE_PARSER(sourced(construct( verbatim("ERROR"_tok), Parser{}))) TYPE_PARSER(sourced(construct("NOTHING" >> ok))) TYPE_PARSER(sourced(construct( sourced(construct( sourced(Parser{}))) || sourced(construct( sourced(Parser{})))))) TYPE_PARSER(sourced(construct( "METADIRECTIVE" >> Parser{}))) // Omp directives enclosing do loop TYPE_PARSER(sourced(construct(first( "DISTRIBUTE PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_distribute_parallel_do_simd), "DISTRIBUTE PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_distribute_parallel_do), "DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_distribute_simd), "DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_distribute), "DO SIMD" >> pure(llvm::omp::Directive::OMPD_do_simd), "DO" >> pure(llvm::omp::Directive::OMPD_do), "LOOP" >> pure(llvm::omp::Directive::OMPD_loop), "MASKED TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_masked_taskloop_simd), "MASKED TASKLOOP" >> pure(llvm::omp::Directive::OMPD_masked_taskloop), "MASTER TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_master_taskloop_simd), "MASTER TASKLOOP" >> pure(llvm::omp::Directive::OMPD_master_taskloop), "PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_do_simd), "PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_parallel_do), "PARALLEL MASKED TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop_simd), "PARALLEL MASKED TASKLOOP" >> pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop), "PARALLEL MASTER TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_master_taskloop_simd), "PARALLEL MASTER TASKLOOP" >> pure(llvm::omp::Directive::OMPD_parallel_master_taskloop), "SIMD" >> pure(llvm::omp::Directive::OMPD_simd), "TARGET LOOP" >> pure(llvm::omp::Directive::OMPD_target_loop), "TARGET PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_target_parallel_do_simd), "TARGET PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_target_parallel_do), "TARGET PARALLEL LOOP" >> pure(llvm::omp::Directive::OMPD_target_parallel_loop), "TARGET SIMD" >> pure(llvm::omp::Directive::OMPD_target_simd), "TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD" >> pure(llvm::omp::Directive:: OMPD_target_teams_distribute_parallel_do_simd), "TARGET TEAMS DISTRIBUTE PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do), "TARGET TEAMS DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_target_teams_distribute_simd), "TARGET TEAMS DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_target_teams_distribute), "TARGET TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_target_teams_loop), "TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_taskloop_simd), "TASKLOOP" >> pure(llvm::omp::Directive::OMPD_taskloop), "TEAMS DISTRIBUTE PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd), "TEAMS DISTRIBUTE PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do), "TEAMS DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_teams_distribute_simd), "TEAMS DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_teams_distribute), "TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_teams_loop), "TILE" >> pure(llvm::omp::Directive::OMPD_tile), "UNROLL" >> pure(llvm::omp::Directive::OMPD_unroll))))) TYPE_PARSER(sourced(construct( sourced(Parser{}), Parser{}))) // 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP TYPE_PARSER(sourced(construct( first("PARALLEL" >> pure(OmpCancelType::Type::Parallel), "SECTIONS" >> pure(OmpCancelType::Type::Sections), "DO" >> pure(OmpCancelType::Type::Do), "TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup))))) // 2.14.2 Cancellation Point construct TYPE_PARSER(sourced(construct( verbatim("CANCELLATION POINT"_tok), Parser{}))) // 2.14.1 Cancel construct TYPE_PARSER(sourced(construct(verbatim("CANCEL"_tok), Parser{}, maybe("IF" >> parenthesized(scalarLogicalExpr))))) TYPE_PARSER(sourced(construct( parenthesized(indirect(Parser{}))))) // 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0] // memory-order-clause -> // seq_cst // acq_rel // release // acquire // relaxed TYPE_PARSER(sourced(construct( sourced("SEQ_CST" >> construct(construct()) || "ACQ_REL" >> construct(construct()) || "RELEASE" >> construct(construct()) || "ACQUIRE" >> construct(construct()) || "RELAXED" >> construct(construct()))))) // 2.4 Requires construct [OpenMP 5.0] // atomic-default-mem-order-clause -> // seq_cst // acq_rel // relaxed TYPE_PARSER(construct( "SEQ_CST" >> pure(common::OmpAtomicDefaultMemOrderType::SeqCst) || "ACQ_REL" >> pure(common::OmpAtomicDefaultMemOrderType::AcqRel) || "RELAXED" >> pure(common::OmpAtomicDefaultMemOrderType::Relaxed))) // 2.17.7 Atomic construct // atomic-clause -> memory-order-clause | HINT(hint-expression) TYPE_PARSER(sourced(construct( construct(Parser{}) || construct("FAIL" >> Parser{}) || construct("HINT" >> sourced(construct( construct(parenthesized(constantExpr)))))))) // atomic-clause-list -> [atomic-clause, [atomic-clause], ...] TYPE_PARSER(sourced(construct( many(maybe(","_tok) >> sourced(Parser{}))))) TYPE_PARSER(sourced(construct(verbatim("DEPOBJ"_tok), parenthesized(Parser{}), sourced(Parser{})))) TYPE_PARSER(sourced(construct(verbatim("FLUSH"_tok), many(maybe(","_tok) >> sourced(Parser{})), maybe(parenthesized(Parser{}))))) // Simple Standalone Directives TYPE_PARSER(sourced(construct(first( "BARRIER" >> pure(llvm::omp::Directive::OMPD_barrier), "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered), "SCAN" >> pure(llvm::omp::Directive::OMPD_scan), "TARGET ENTER DATA" >> pure(llvm::omp::Directive::OMPD_target_enter_data), "TARGET EXIT DATA" >> pure(llvm::omp::Directive::OMPD_target_exit_data), "TARGET UPDATE" >> pure(llvm::omp::Directive::OMPD_target_update), "TASKWAIT" >> pure(llvm::omp::Directive::OMPD_taskwait), "TASKYIELD" >> pure(llvm::omp::Directive::OMPD_taskyield))))) TYPE_PARSER(sourced(construct( Parser{}, Parser{}))) // Standalone Constructs TYPE_PARSER( sourced(construct( Parser{}) || construct(Parser{}) || construct(Parser{}) || construct( Parser{}) || construct( Parser{}) || construct(Parser{})) / endOfLine) // Directives enclosing structured-block TYPE_PARSER(construct(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 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( sourced(Parser{}), Parser{}))) TYPE_PARSER(construct( "INITIALIZER" >> parenthesized("OMP_PRIV =" >> expr))) // 2.16 Declare Reduction Construct TYPE_PARSER(sourced(construct( verbatim("DECLARE REDUCTION"_tok), "(" >> Parser{} / ":", nonemptyList(Parser{}) / ":", Parser{} / ")", maybe(Parser{})))) // declare-target with list TYPE_PARSER(sourced(construct( parenthesized(Parser{})))) // declare-target with clause TYPE_PARSER( sourced(construct(Parser{}))) // declare-target-specifier TYPE_PARSER( construct(Parser{}) || construct(Parser{})) // 2.10.6 Declare Target Construct TYPE_PARSER(sourced(construct( verbatim("DECLARE TARGET"_tok), Parser{}))) // declare-mapper-specifier TYPE_PARSER(construct( maybe(name / ":" / !":"_tok), typeSpec / "::", name)) // OpenMP 5.2: 5.8.8 Declare Mapper Construct TYPE_PARSER(sourced(construct( verbatim("DECLARE MAPPER"_tok), "(" >> Parser{} / ")", Parser{}))) TYPE_PARSER(construct(Parser{}) || construct( construct( construct(Parser{}, parenthesized(optionalList(actualArgSpec)))))) // 2.17.7 atomic -> ATOMIC [clause [,]] atomic-clause [[,] clause] | // ATOMIC [clause] // clause -> memory-order-clause | HINT(hint-expression) // memory-order-clause -> SEQ_CST | ACQ_REL | RELEASE | ACQUIRE | RELAXED // atomic-clause -> READ | WRITE | UPDATE | CAPTURE // OMP END ATOMIC TYPE_PARSER(construct(startOmpLine >> "END ATOMIC"_tok)) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] READ [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> sourced(construct( Parser{} / maybe(","_tok), verbatim("READ"_tok), Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine)))) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] CAPTURE [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> sourced(construct( Parser{} / maybe(","_tok), verbatim("CAPTURE"_tok), Parser{} / endOmpLine, statement(assignmentStmt), statement(assignmentStmt), Parser{} / endOmpLine))) TYPE_PARSER(construct(indirect(Parser{})) || construct(indirect(Parser{}))) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] COMPARE [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> sourced(construct( Parser{} / maybe(","_tok), verbatim("COMPARE"_tok), Parser{} / endOmpLine, Parser{}, maybe(Parser{} / endOmpLine)))) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> sourced(construct( Parser{} / maybe(","_tok), verbatim("UPDATE"_tok), Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine)))) // OMP ATOMIC [atomic-clause-list] TYPE_PARSER(sourced(construct(verbatim("ATOMIC"_tok), Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine)))) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] WRITE [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> sourced(construct( Parser{} / maybe(","_tok), verbatim("WRITE"_tok), Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine)))) // Atomic Construct TYPE_PARSER(construct(Parser{}) || construct(Parser{}) || construct(Parser{}) || construct(Parser{}) || construct(Parser{}) || construct(Parser{})) // 2.13.2 OMP CRITICAL TYPE_PARSER(startOmpLine >> sourced(construct( verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) / endOmpLine) TYPE_PARSER(sourced(construct(verbatim("CRITICAL"_tok), maybe(parenthesized(name)), Parser{})) / endOmpLine) TYPE_PARSER(construct( Parser{}, block, Parser{})) TYPE_PARSER(sourced(construct( verbatim("DISPATCH"_tok), Parser{}))) TYPE_PARSER( construct(startOmpLine >> "END DISPATCH"_tok)) TYPE_PARSER(sourced(construct( Parser{} / endOmpLine, block, maybe(Parser{} / endOmpLine)))) // 2.11.3 Executable Allocate directive TYPE_PARSER( sourced(construct(verbatim("ALLOCATE"_tok), maybe(parenthesized(Parser{})), Parser{}, maybe(nonemptyList(Parser{})) / endOmpLine, statement(allocateStmt)))) // 6.7 Allocators construct [OpenMP 5.2] // allocators-construct -> ALLOCATORS [allocate-clause [,]] // allocate-stmt // [omp-end-allocators-construct] TYPE_PARSER(sourced(construct( verbatim("ALLOCATORS"_tok), Parser{} / endOmpLine, statement(allocateStmt), maybe(Parser{} / endOmpLine)))) TYPE_PARSER(construct(startOmpLine >> "END ALLOCATORS"_tok)) // 2.8.2 Declare Simd construct TYPE_PARSER( sourced(construct(verbatim("DECLARE SIMD"_tok), maybe(parenthesized(name)), Parser{}))) // 2.4 Requires construct TYPE_PARSER(sourced(construct( verbatim("REQUIRES"_tok), Parser{}))) // 2.15.2 Threadprivate directive TYPE_PARSER(sourced(construct( verbatim("THREADPRIVATE"_tok), parenthesized(Parser{})))) // 2.11.3 Declarative Allocate directive TYPE_PARSER( sourced(construct(verbatim("ALLOCATE"_tok), parenthesized(Parser{}), Parser{})) / lookAhead(endOmpLine / !statement(allocateStmt))) // Declarative constructs TYPE_PARSER(startOmpLine >> withMessage("expected OpenMP construct"_err_en_US, sourced(construct( Parser{}) || construct( Parser{}) || construct( Parser{}) || construct( Parser{}) || construct( Parser{}) || construct( Parser{}) || construct( Parser{}) || construct( Parser{})) / endOmpLine)) // Block Construct TYPE_PARSER(construct( Parser{} / endOmpLine, block, Parser{} / endOmpLine)) // OMP SECTIONS Directive TYPE_PARSER(construct(first( "SECTIONS" >> pure(llvm::omp::Directive::OMPD_sections), "PARALLEL SECTIONS" >> pure(llvm::omp::Directive::OMPD_parallel_sections)))) // OMP BEGIN and END SECTIONS Directive TYPE_PARSER(sourced(construct( sourced(Parser{}), Parser{}))) TYPE_PARSER( startOmpLine >> sourced(construct( sourced("END"_tok >> Parser{}), Parser{}))) // OMP SECTION-BLOCK TYPE_PARSER(construct(block)) TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >> construct(nonemptySeparated( construct(sourced(Parser{})), startOmpLine >> "SECTION"_tok / endOmpLine))) // OMP SECTIONS (OpenMP 5.0 - 2.8.1), PARALLEL SECTIONS (OpenMP 5.0 - 2.13.3) TYPE_PARSER(construct( Parser{} / endOmpLine, Parser{}, Parser{} / endOmpLine)) TYPE_CONTEXT_PARSER("OpenMP construct"_en_US, startOmpLine >> withMessage("expected OpenMP construct"_err_en_US, first(construct(Parser{}), construct(Parser{}), construct(Parser{}), // OpenMPBlockConstruct is attempted before // OpenMPStandaloneConstruct to resolve !$OMP ORDERED construct(Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{})))) // END OMP Block directives TYPE_PARSER( startOmpLine >> sourced(construct( sourced("END"_tok >> Parser{}), Parser{}))) // END OMP Loop directives TYPE_PARSER( startOmpLine >> sourced(construct( sourced("END"_tok >> Parser{}), Parser{}))) TYPE_PARSER(construct( Parser{} / endOmpLine)) } // namespace Fortran::parser