//===-- 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" // OpenMP Directives and Clauses namespace Fortran::parser { constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok; constexpr auto endOmpLine = space >> endOfLine; // Helper class to deal with a list of modifiers of various types. // The list (to be parsed) is assumed to start with all modifiers of the // first type, followed by a list of modifiers of the second type, etc. // Each list can be empty, e.g. // mod_of_kind_2, mod_of_kind_3, mod_of_kind_5, ... // The result type is a tuple of optional lists of each modifier type. template struct ConcatSeparated { template using OptListOf = std::optional>; template using TupleFor = std::tuple>; using resultType = std::tuple, OptListOf...>; constexpr ConcatSeparated(ConcatSeparated &&) = default; constexpr ConcatSeparated(const ConcatSeparated &) = default; constexpr ConcatSeparated(Separator sep, Parser p, Parsers... ps) : parser_(p), sepAndParsers_(sep, ps...) {} std::optional Parse(ParseState &state) const { // firstParser is a list parser, it returns optional. auto firstParser = attempt(nonemptySeparated(parser_, std::get<0>(sepAndParsers_))); if constexpr (sizeof...(Parsers) == 0) { return TupleFor{std::move(firstParser.Parse(state))}; } else { using restParserType = ConcatSeparated; auto restParser = std::make_from_tuple(sepAndParsers_); if (auto first{firstParser.Parse(state)}) { if (attempt(std::get<0>(sepAndParsers_)).Parse(state)) { return std::tuple_cat(TupleFor(std::move(*first)), std::move(*restParser.Parse(state))); } return std::tuple_cat(TupleFor{std::move(*first)}, std::tuple...>{}); } return std::tuple_cat( TupleFor{}, std::move(*restParser.Parse(state))); } } private: const Parser parser_; const std::tuple sepAndParsers_; }; // Map modifiers come from four categories: // - map-type-modifier, // - mapper (not parsed yet), // - iterator, // - map-type. // There can be zero or more map-type-modifiers, and zero or one modifier // of every other kind. // Syntax-wise they look like a single list, where the last element could // be a map-type, and all elements in that list are comma-separated[1]. // Only if there was at least one modifier (of any kind) specified, the // list must end with ":". // There are complications coming from the fact that the comma separating the // two kinds of modifiers is only allowed if there is at least one modifier of // each kind. The MapModifiers parser utilizes the ConcatSeparated parser, which // takes care of that. ConcatSeparated returns a tuple with optional lists of // modifiers for every type. // [1] Any of the commas are optional, but that syntax has been deprecated // in OpenMP 5.2, and the parsing code keeps a record of whether the commas // were present. template struct MapModifiers { constexpr MapModifiers(Separator sep) : sep_(sep) {} constexpr MapModifiers(const MapModifiers &) = default; constexpr MapModifiers(MapModifiers &&) = default; // Parsing of mappers is not supported yet. using TypeModParser = Parser; using IterParser = Parser; using TypeParser = Parser; using ModParser = ConcatSeparated; using resultType = typename ModParser::resultType; std::optional Parse(ParseState &state) const { auto mp = ModParser(sep_, TypeModParser{}, IterParser{}, TypeParser{}); auto mods = mp.Parse(state); // The ModParser always "succeeds", i.e. even if the input is junk, it // will return a tuple filled with nullopts. If any of the components // is not a nullopt, expect a ":". if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) { if (!attempt(":"_tok).Parse(state)) { return std::nullopt; } } return std::move(mods); } private: const Separator sep_; }; // 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(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{}))))) // [5.0] 2.10.1 affinity([aff-modifier:] locator-list) // aff-modifier: interator-modifier TYPE_PARSER(construct( maybe(Parser{} / ":"), Parser{})) // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) TYPE_PARSER(construct( "PRIVATE" >> pure(OmpDefaultClause::Type::Private) || "FIRSTPRIVATE" >> pure(OmpDefaultClause::Type::Firstprivate) || "SHARED" >> pure(OmpDefaultClause::Type::Shared) || "NONE" >> pure(OmpDefaultClause::Type::None))) // 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD ) TYPE_PARSER(construct( "CLOSE" >> pure(OmpProcBindClause::Type::Close) || "MASTER" >> pure(OmpProcBindClause::Type::Master) || "PRIMARY" >> pure(OmpProcBindClause::Type::Primary) || "SPREAD" >> pure(OmpProcBindClause::Type::Spread))) // 2.15.5.1 map -> // MAP ([ [map-type-modifiers [,] ] map-type : ] variable-name-list) // map-type-modifiers -> map-type-modifier [,] [...] // map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT // map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM TYPE_PARSER(construct( "ALWAYS" >> pure(OmpMapClause::TypeModifier::Always) || "CLOSE" >> pure(OmpMapClause::TypeModifier::Close) || "OMPX_HOLD" >> pure(OmpMapClause::TypeModifier::Ompx_Hold) || "PRESENT" >> pure(OmpMapClause::TypeModifier::Present))) TYPE_PARSER( construct("ALLOC" >> pure(OmpMapClause::Type::Alloc) || "DELETE" >> pure(OmpMapClause::Type::Delete) || "FROM" >> pure(OmpMapClause::Type::From) || "RELEASE" >> pure(OmpMapClause::Type::Release) || "TO"_id >> pure(OmpMapClause::Type::To) || "TOFROM" >> pure(OmpMapClause::Type::Tofrom))) template static inline OmpMapClause makeMapClause( std::tuple>, std::optional>, std::optional>> &&mods, OmpObjectList &&objs) { auto &&[tm, it, ty] = std::move(mods); return OmpMapClause{std::move(tm), std::move(it), std::move(ty), std::move(objs), CommasEverywhere}; } TYPE_PARSER(construct( applyFunction( makeMapClause, MapModifiers(","_tok), Parser{}) || applyFunction(makeMapClause, MapModifiers(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 -> 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(":" >> construct( "SCALAR" >> pure(OmpDefaultmapClause::VariableCategory::Scalar) || "AGGREGATE" >> pure(OmpDefaultmapClause::VariableCategory::Aggregate) || "ALLOCATABLE" >> pure(OmpDefaultmapClause::VariableCategory::Allocatable) || "POINTER" >> pure(OmpDefaultmapClause::VariableCategory::Pointer))))) // 2.7.1 SCHEDULE ([modifier1 [, modifier2]:]kind[, chunk_size]) // Modifier -> MONITONIC | NONMONOTONIC | SIMD // kind -> STATIC | DYNAMIC | GUIDED | AUTO | RUNTIME // chunk_size -> ScalarIntExpr TYPE_PARSER(construct( "MONOTONIC" >> pure(OmpScheduleModifierType::ModType::Monotonic) || "NONMONOTONIC" >> pure(OmpScheduleModifierType::ModType::Nonmonotonic) || "SIMD" >> pure(OmpScheduleModifierType::ModType::Simd))) TYPE_PARSER(construct(Parser{}, maybe("," >> Parser{}) / ":")) TYPE_PARSER(construct(maybe(Parser{}), "STATIC" >> pure(OmpScheduleClause::ScheduleType::Static) || "DYNAMIC" >> pure(OmpScheduleClause::ScheduleType::Dynamic) || "GUIDED" >> pure(OmpScheduleClause::ScheduleType::Guided) || "AUTO" >> pure(OmpScheduleClause::ScheduleType::Auto) || "RUNTIME" >> pure(OmpScheduleClause::ScheduleType::Runtime), maybe("," >> scalarIntExpr))) // device([ device-modifier :] scalar-integer-expression) TYPE_PARSER(construct( maybe( ("ANCESTOR" >> pure(OmpDeviceClause::DeviceModifier::Ancestor) || "DEVICE_NUM" >> pure(OmpDeviceClause::DeviceModifier::Device_Num)) / ":"), scalarIntExpr)) // device_type(any | host | nohost) TYPE_PARSER(construct( "ANY" >> pure(OmpDeviceTypeClause::Type::Any) || "HOST" >> pure(OmpDeviceTypeClause::Type::Host) || "NOHOST" >> pure(OmpDeviceTypeClause::Type::Nohost))) // 2.12 IF (directive-name-modifier: scalar-logical-expr) TYPE_PARSER(construct( maybe( ("PARALLEL" >> pure(OmpIfClause::DirectiveNameModifier::Parallel) || "SIMD" >> pure(OmpIfClause::DirectiveNameModifier::Simd) || "TARGET ENTER DATA" >> pure(OmpIfClause::DirectiveNameModifier::TargetEnterData) || "TARGET EXIT DATA" >> pure(OmpIfClause::DirectiveNameModifier::TargetExitData) || "TARGET DATA" >> pure(OmpIfClause::DirectiveNameModifier::TargetData) || "TARGET UPDATE" >> pure(OmpIfClause::DirectiveNameModifier::TargetUpdate) || "TARGET" >> pure(OmpIfClause::DirectiveNameModifier::Target) || "TASK"_id >> pure(OmpIfClause::DirectiveNameModifier::Task) || "TASKLOOP" >> pure(OmpIfClause::DirectiveNameModifier::Taskloop) || "TEAMS" >> pure(OmpIfClause::DirectiveNameModifier::Teams)) / ":"), scalarLogicalExpr)) // 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list) TYPE_PARSER(construct(Parser{}) || construct(Parser{})) TYPE_PARSER(construct( maybe( ("INSCAN" >> pure(OmpReductionClause::ReductionModifier::Inscan) || "TASK" >> pure(OmpReductionClause::ReductionModifier::Task) || "DEFAULT" >> pure(OmpReductionClause::ReductionModifier::Default)) / ","), Parser{} / ":", Parser{})) // OMP 5.0 2.19.5.6 IN_REDUCTION (reduction-identifier: variable-name-list) TYPE_PARSER(construct( 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( first( construct("ALLOCATOR" >> construct( parenthesized(construct< OmpAllocateClause::AllocateModifier::Allocator>( scalarIntExpr)) / ",", "ALIGN" >> parenthesized(construct< OmpAllocateClause::AllocateModifier::Align>( scalarIntExpr)))), construct("ALLOCATOR" >> parenthesized( construct( scalarIntExpr))), construct("ALIGN" >> parenthesized( construct( scalarIntExpr))), construct( construct( scalarIntExpr))) / ":"), Parser{})) // 2.13.9 DEPEND (SOURCE | SINK : vec | (IN | OUT | INOUT) : list TYPE_PARSER(construct( Parser{}, scalarIntConstantExpr)) TYPE_PARSER( construct(name, maybe(Parser{}))) TYPE_PARSER(construct( "IN"_id >> pure(OmpTaskDependenceType::Type::In) || "INOUT" >> pure(OmpTaskDependenceType::Type::Inout) || "OUT" >> pure(OmpTaskDependenceType::Type::Out))) TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, construct(construct( "SINK :" >> nonemptyList(Parser{}))) || construct( construct("SOURCE"_tok)) || construct(construct( maybe(Parser{} / ","_tok), Parser{} / ":", Parser{}))) // 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::Type::Ref) || "VAL" >> pure(OmpLinearModifier::Type::Val) || "UVAL" >> pure(OmpLinearModifier::Type::Uval))) TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US, construct( construct(construct( Parser{}, parenthesized(nonemptyList(name)), maybe(":" >> scalarIntConstantExpr))) || construct(construct( nonemptyList(name), maybe(":" >> scalarIntConstantExpr))))) // 2.8.1 ALIGNED (list: alignment) TYPE_PARSER(construct( Parser{}, maybe(":" >> scalarIntConstantExpr))) // 2.9.5 ORDER ([order-modifier :]concurrent) TYPE_PARSER(construct( "REPRODUCIBLE" >> pure(OmpOrderModifier::Kind::Reproducible)) || construct( "UNCONSTRAINED" >> pure(OmpOrderModifier::Kind::Unconstrained))) TYPE_PARSER(construct( maybe(Parser{} / ":"), "CONCURRENT" >> pure(OmpOrderClause::Type::Concurrent))) // OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression) TYPE_PARSER(construct( maybe("STRICT" >> pure(OmpGrainsizeClause::Prescriptiveness::Strict) / ":"), scalarIntExpr)) // OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression) TYPE_PARSER(construct( maybe("STRICT" >> pure(OmpNumTasksClause::Prescriptiveness::Strict) / ":"), scalarIntExpr)) TYPE_PARSER( construct(designator) || construct("/" >> name / "/")) // OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list) TYPE_PARSER(construct( maybe("CONDITIONAL" >> pure(OmpLastprivateClause::LastprivateModifier::Conditional) / ":"), Parser{})) TYPE_PARSER( "ACQUIRE" >> construct(construct()) || "ACQ_REL" >> construct(construct()) || "AFFINITY" >> construct(construct( parenthesized(Parser{}))) || "ALIGNED" >> construct(construct( parenthesized(Parser{}))) || "ALLOCATE" >> construct(construct( parenthesized(Parser{}))) || "ALLOCATOR" >> construct(construct( parenthesized(scalarIntExpr))) || "ATOMIC_DEFAULT_MEM_ORDER" >> 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{}))) || "DEVICE" >> construct(construct( parenthesized(Parser{}))) || "DEVICE_TYPE" >> construct(construct( parenthesized(Parser{}))) || "DIST_SCHEDULE" >> construct(construct( parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) || "DYNAMIC_ALLOCATORS" >> construct(construct()) || "ENTER" >> construct(construct( parenthesized(Parser{}))) || "FILTER" >> construct(construct( parenthesized(scalarIntExpr))) || "FINAL" >> construct(construct( parenthesized(scalarLogicalExpr))) || "FULL" >> construct(construct()) || "FIRSTPRIVATE" >> construct(construct( parenthesized(Parser{}))) || "FROM" >> construct(construct( parenthesized(Parser{}))) || "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()) || "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{}))) || "MERGEABLE" >> construct(construct()) || "NOGROUP" >> construct(construct()) || "NONTEMPORAL" >> construct(construct( parenthesized(nonemptyList(name)))) || "NOTINBRANCH" >> construct(construct()) || "NOWAIT" >> construct(construct()) || "NUM_TASKS" >> construct(construct( parenthesized(Parser{}))) || "NUM_TEAMS" >> construct(construct( parenthesized(scalarIntExpr))) || "NUM_THREADS" >> construct(construct( parenthesized(scalarIntExpr))) || "ORDER" >> construct(construct( parenthesized(Parser{}))) || "ORDERED" >> construct(construct( maybe(parenthesized(scalarIntConstantExpr)))) || "PARTIAL" >> construct(construct( maybe(parenthesized(scalarIntConstantExpr)))) || "PRIORITY" >> construct(construct( parenthesized(scalarIntExpr))) || "PRIVATE" >> construct(construct( parenthesized(Parser{}))) || "PROC_BIND" >> construct(construct( parenthesized(Parser{}))) || "REDUCTION" >> construct(construct( parenthesized(Parser{}))) || "IN_REDUCTION" >> 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()) || "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())) // [Clause, [Clause], ...] TYPE_PARSER(sourced(construct( many(maybe(","_tok) >> sourced(Parser{}))))) // 2.1 (variable | /common-block | array-sections) TYPE_PARSER(construct(nonemptyList(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), "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))))) // 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("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("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), "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{})) / 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{}))) 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))) // 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{})) // 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{})) // 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{})) / 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{})))) // 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