1 //===-- lib/Parser/openmp-parsers.cpp -------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // Top-level grammar specification for OpenMP. 10 // See OpenMP-4.5-grammar.txt for documentation. 11 12 #include "basic-parsers.h" 13 #include "expr-parsers.h" 14 #include "misc-parsers.h" 15 #include "stmt-parser.h" 16 #include "token-parsers.h" 17 #include "type-parser-implementation.h" 18 #include "flang/Parser/parse-tree.h" 19 20 // OpenMP Directives and Clauses 21 namespace Fortran::parser { 22 23 constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok; 24 constexpr auto endOmpLine = space >> endOfLine; 25 26 // Helper class to deal with a list of modifiers of various types. 27 // The list (to be parsed) is assumed to start with all modifiers of the 28 // first type, followed by a list of modifiers of the second type, etc. 29 // Each list can be empty, e.g. 30 // mod_of_kind_2, mod_of_kind_3, mod_of_kind_5, ... 31 // The result type is a tuple of optional lists of each modifier type. 32 template <typename Separator, typename Parser, typename... Parsers> 33 struct ConcatSeparated { 34 template <typename P> 35 using OptListOf = std::optional<std::list<typename P::resultType>>; 36 template <typename P> using TupleFor = std::tuple<OptListOf<P>>; 37 38 using resultType = std::tuple<OptListOf<Parser>, OptListOf<Parsers>...>; 39 40 constexpr ConcatSeparated(ConcatSeparated &&) = default; 41 constexpr ConcatSeparated(const ConcatSeparated &) = default; 42 constexpr ConcatSeparated(Separator sep, Parser p, Parsers... ps) 43 : parser_(p), sepAndParsers_(sep, ps...) {} 44 45 std::optional<resultType> Parse(ParseState &state) const { 46 // firstParser is a list parser, it returns optional<list>. 47 auto firstParser = 48 attempt(nonemptySeparated(parser_, std::get<0>(sepAndParsers_))); 49 50 if constexpr (sizeof...(Parsers) == 0) { 51 return TupleFor<Parser>{std::move(firstParser.Parse(state))}; 52 } else { 53 using restParserType = ConcatSeparated<Separator, Parsers...>; 54 auto restParser = std::make_from_tuple<restParserType>(sepAndParsers_); 55 56 if (auto first{firstParser.Parse(state)}) { 57 if (attempt(std::get<0>(sepAndParsers_)).Parse(state)) { 58 return std::tuple_cat(TupleFor<Parser>(std::move(*first)), 59 std::move(*restParser.Parse(state))); 60 } 61 return std::tuple_cat(TupleFor<Parser>{std::move(*first)}, 62 std::tuple<OptListOf<Parsers>...>{}); 63 } 64 return std::tuple_cat( 65 TupleFor<Parser>{}, std::move(*restParser.Parse(state))); 66 } 67 } 68 69 private: 70 const Parser parser_; 71 const std::tuple<Separator, Parsers...> sepAndParsers_; 72 }; 73 74 // Map modifiers come from four categories: 75 // - map-type-modifier, 76 // - mapper (not parsed yet), 77 // - iterator, 78 // - map-type. 79 // There can be zero or more map-type-modifiers, and zero or one modifier 80 // of every other kind. 81 // Syntax-wise they look like a single list, where the last element could 82 // be a map-type, and all elements in that list are comma-separated[1]. 83 // Only if there was at least one modifier (of any kind) specified, the 84 // list must end with ":". 85 // There are complications coming from the fact that the comma separating the 86 // two kinds of modifiers is only allowed if there is at least one modifier of 87 // each kind. The MapModifiers parser utilizes the ConcatSeparated parser, which 88 // takes care of that. ConcatSeparated returns a tuple with optional lists of 89 // modifiers for every type. 90 // [1] Any of the commas are optional, but that syntax has been deprecated 91 // in OpenMP 5.2, and the parsing code keeps a record of whether the commas 92 // were present. 93 template <typename Separator> struct MapModifiers { 94 constexpr MapModifiers(Separator sep) : sep_(sep) {} 95 constexpr MapModifiers(const MapModifiers &) = default; 96 constexpr MapModifiers(MapModifiers &&) = default; 97 98 // Parsing of mappers is not supported yet. 99 using TypeModParser = Parser<OmpMapClause::TypeModifier>; 100 using IterParser = Parser<OmpIterator>; 101 using TypeParser = Parser<OmpMapClause::Type>; 102 using ModParser = 103 ConcatSeparated<Separator, TypeModParser, IterParser, TypeParser>; 104 105 using resultType = typename ModParser::resultType; 106 107 std::optional<resultType> Parse(ParseState &state) const { 108 auto mp = ModParser(sep_, TypeModParser{}, IterParser{}, TypeParser{}); 109 auto mods = mp.Parse(state); 110 // The ModParser always "succeeds", i.e. even if the input is junk, it 111 // will return a tuple filled with nullopts. If any of the components 112 // is not a nullopt, expect a ":". 113 if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) { 114 if (!attempt(":"_tok).Parse(state)) { 115 return std::nullopt; 116 } 117 } 118 return std::move(mods); 119 } 120 121 private: 122 const Separator sep_; 123 }; 124 125 // This is almost exactly the same thing as MapModifiers. It has the same 126 // issue (it expects modifiers in a specific order), and the fix for that 127 // will change how modifiers are parsed. Instead of making this code more 128 // generic, make it simple, and generalize after the fix is in place. 129 template <typename Separator> struct MotionModifiers { 130 constexpr MotionModifiers(Separator sep) : sep_(sep) {} 131 constexpr MotionModifiers(const MotionModifiers &) = default; 132 constexpr MotionModifiers(MotionModifiers &&) = default; 133 134 using ExpParser = Parser<OmpFromClause::Expectation>; 135 using IterParser = Parser<OmpIterator>; 136 using ModParser = ConcatSeparated<Separator, ExpParser, IterParser>; 137 138 using resultType = typename ModParser::resultType; 139 140 std::optional<resultType> Parse(ParseState &state) const { 141 auto mp{ModParser(sep_, ExpParser{}, IterParser{})}; 142 auto mods{mp.Parse(state)}; 143 // The ModParser always "succeeds", i.e. even if the input is junk, it 144 // will return a tuple filled with nullopts. If any of the components 145 // is not a nullopt, expect a ":". 146 if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) { 147 if (!attempt(":"_tok).Parse(state)) { 148 return std::nullopt; 149 } 150 } 151 return std::move(mods); 152 } 153 154 private: 155 const Separator sep_; 156 }; 157 158 // OpenMP Clauses 159 160 // [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple | 161 // identifier = subscript-triple 162 // [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not 163 // specified then the type of that iterator is default integer. 164 // [5.0:49:14] The iterator-type must be an integer type. 165 static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) { 166 std::list<EntityDecl> entities; 167 168 for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) { 169 EntityDecl entityDecl( 170 /*ObjectName=*/std::move(*iter), std::optional<ArraySpec>{}, 171 std::optional<CoarraySpec>{}, std::optional<CharLength>{}, 172 std::optional<Initialization>{}); 173 entities.push_back(std::move(entityDecl)); 174 } 175 return entities; 176 } 177 178 static TypeDeclarationStmt makeIterSpecDecl( 179 DeclarationTypeSpec &&spec, std::list<ObjectName> &&names) { 180 return TypeDeclarationStmt( 181 std::move(spec), std::list<AttrSpec>{}, makeEntityList(std::move(names))); 182 } 183 184 static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) { 185 // Assume INTEGER without kind selector. 186 DeclarationTypeSpec typeSpec( 187 IntrinsicTypeSpec{IntegerTypeSpec{std::nullopt}}); 188 189 return TypeDeclarationStmt(std::move(typeSpec), std::list<AttrSpec>{}, 190 makeEntityList(std::move(names))); 191 } 192 193 // --- Parsers for clause modifiers ----------------------------------- 194 195 TYPE_PARSER(construct<OmpIteratorSpecifier>( 196 // Using Parser<TypeDeclarationStmt> or Parser<EntityDecl> has the problem 197 // that they will attempt to treat what follows the '=' as initialization. 198 // There are several issues with that, 199 // 1. integer :: i = 0:10 will be parsed as "integer :: i = 0", followed 200 // by triplet ":10". 201 // 2. integer :: j = i:10 will be flagged as an error because the 202 // initializer 'i' must be constant (in declarations). In an iterator 203 // specifier the 'j' is not an initializer and can be a variable. 204 (applyFunction<TypeDeclarationStmt>(makeIterSpecDecl, 205 Parser<DeclarationTypeSpec>{} / maybe("::"_tok), 206 nonemptyList(Parser<ObjectName>{}) / "="_tok) || 207 applyFunction<TypeDeclarationStmt>( 208 makeIterSpecDecl, nonemptyList(Parser<ObjectName>{}) / "="_tok)), 209 subscriptTriplet)) 210 211 TYPE_PARSER(construct<OmpDependenceType>( 212 "SINK" >> pure(OmpDependenceType::Value::Sink) || 213 "SOURCE" >> pure(OmpDependenceType::Value::Source))) 214 215 // [5.0] 2.1.6 iterator -> iterator-specifier-list 216 TYPE_PARSER(construct<OmpIterator>("ITERATOR" >> 217 parenthesized(nonemptyList(sourced(Parser<OmpIteratorSpecifier>{}))))) 218 219 // 2.15.3.7 LINEAR (linear-list: linear-step) 220 // linear-list -> list | modifier(list) 221 // linear-modifier -> REF | VAL | UVAL 222 TYPE_PARSER(construct<OmpLinearModifier>( // 223 "REF" >> pure(OmpLinearModifier::Value::Ref) || 224 "VAL" >> pure(OmpLinearModifier::Value::Val) || 225 "UVAL" >> pure(OmpLinearModifier::Value::Uval))) 226 227 // 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list) 228 TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) || 229 construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{})) 230 231 TYPE_PARSER(construct<OmpTaskDependenceType>( 232 "DEPOBJ" >> pure(OmpTaskDependenceType::Value::Depobj) || 233 "IN"_id >> pure(OmpTaskDependenceType::Value::In) || 234 "INOUT"_id >> pure(OmpTaskDependenceType::Value::Inout) || 235 "INOUTSET"_id >> pure(OmpTaskDependenceType::Value::Inoutset) || 236 "MUTEXINOUTSET" >> pure(OmpTaskDependenceType::Value::Mutexinoutset) || 237 "OUT" >> pure(OmpTaskDependenceType::Value::Out))) 238 239 // --- Parsers for clauses -------------------------------------------- 240 241 // [5.0] 2.10.1 affinity([aff-modifier:] locator-list) 242 // aff-modifier: interator-modifier 243 TYPE_PARSER(construct<OmpAffinityClause>( 244 maybe(Parser<OmpIterator>{} / ":"), Parser<OmpObjectList>{})) 245 246 // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) 247 TYPE_PARSER(construct<OmpDefaultClause>( 248 "PRIVATE" >> pure(OmpDefaultClause::Type::Private) || 249 "FIRSTPRIVATE" >> pure(OmpDefaultClause::Type::Firstprivate) || 250 "SHARED" >> pure(OmpDefaultClause::Type::Shared) || 251 "NONE" >> pure(OmpDefaultClause::Type::None))) 252 253 // 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD ) 254 TYPE_PARSER(construct<OmpProcBindClause>( 255 "CLOSE" >> pure(OmpProcBindClause::Type::Close) || 256 "MASTER" >> pure(OmpProcBindClause::Type::Master) || 257 "PRIMARY" >> pure(OmpProcBindClause::Type::Primary) || 258 "SPREAD" >> pure(OmpProcBindClause::Type::Spread))) 259 260 // 2.15.5.1 map -> 261 // MAP ([ [map-type-modifiers [,] ] map-type : ] variable-name-list) 262 // map-type-modifiers -> map-type-modifier [,] [...] 263 // map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT 264 // map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM 265 TYPE_PARSER(construct<OmpMapClause::TypeModifier>( 266 "ALWAYS" >> pure(OmpMapClause::TypeModifier::Always) || 267 "CLOSE" >> pure(OmpMapClause::TypeModifier::Close) || 268 "OMPX_HOLD" >> pure(OmpMapClause::TypeModifier::Ompx_Hold) || 269 "PRESENT" >> pure(OmpMapClause::TypeModifier::Present))) 270 271 TYPE_PARSER( 272 construct<OmpMapClause::Type>("ALLOC" >> pure(OmpMapClause::Type::Alloc) || 273 "DELETE" >> pure(OmpMapClause::Type::Delete) || 274 "FROM" >> pure(OmpMapClause::Type::From) || 275 "RELEASE" >> pure(OmpMapClause::Type::Release) || 276 "TO"_id >> pure(OmpMapClause::Type::To) || 277 "TOFROM" >> pure(OmpMapClause::Type::Tofrom))) 278 279 template <bool CommasEverywhere> 280 static inline OmpMapClause makeMapClause(OmpMapperIdentifier &&mm, 281 std::tuple<std::optional<std::list<OmpMapClause::TypeModifier>>, 282 std::optional<std::list<OmpIterator>>, 283 std::optional<std::list<OmpMapClause::Type>>> &&mods, 284 OmpObjectList &&objs) { 285 auto &&[tm, it, ty] = std::move(mods); 286 return OmpMapClause{std::move(mm), std::move(tm), std::move(it), 287 std::move(ty), std::move(objs), CommasEverywhere}; 288 } 289 290 TYPE_PARSER(construct<OmpMapperIdentifier>( 291 maybe("MAPPER"_tok >> parenthesized(name) / ","_tok))) 292 293 TYPE_PARSER(construct<OmpMapClause>( 294 applyFunction<OmpMapClause>(makeMapClause<true>, 295 Parser<OmpMapperIdentifier>{}, MapModifiers(","_tok), 296 Parser<OmpObjectList>{}) || 297 applyFunction<OmpMapClause>(makeMapClause<false>, 298 Parser<OmpMapperIdentifier>{}, MapModifiers(maybe(","_tok)), 299 Parser<OmpObjectList>{}))) 300 301 // [OpenMP 5.0] 302 // 2.19.7.2 defaultmap(implicit-behavior[:variable-category]) 303 // implicit-behavior -> ALLOC | TO | FROM | TOFROM | FIRSRTPRIVATE | NONE | 304 // DEFAULT 305 // variable-category -> ALL | SCALAR | AGGREGATE | ALLOCATABLE | POINTER 306 TYPE_PARSER(construct<OmpDefaultmapClause>( 307 construct<OmpDefaultmapClause::ImplicitBehavior>( 308 "ALLOC" >> pure(OmpDefaultmapClause::ImplicitBehavior::Alloc) || 309 "TO"_id >> pure(OmpDefaultmapClause::ImplicitBehavior::To) || 310 "FROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::From) || 311 "TOFROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::Tofrom) || 312 "FIRSTPRIVATE" >> 313 pure(OmpDefaultmapClause::ImplicitBehavior::Firstprivate) || 314 "NONE" >> pure(OmpDefaultmapClause::ImplicitBehavior::None) || 315 "DEFAULT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Default)), 316 maybe(":" >> 317 construct<OmpDefaultmapClause::VariableCategory>( 318 "ALL"_id >> pure(OmpDefaultmapClause::VariableCategory::All) || 319 "SCALAR" >> pure(OmpDefaultmapClause::VariableCategory::Scalar) || 320 "AGGREGATE" >> 321 pure(OmpDefaultmapClause::VariableCategory::Aggregate) || 322 "ALLOCATABLE" >> 323 pure(OmpDefaultmapClause::VariableCategory::Allocatable) || 324 "POINTER" >> 325 pure(OmpDefaultmapClause::VariableCategory::Pointer))))) 326 327 // 2.7.1 SCHEDULE ([modifier1 [, modifier2]:]kind[, chunk_size]) 328 // Modifier -> MONITONIC | NONMONOTONIC | SIMD 329 // kind -> STATIC | DYNAMIC | GUIDED | AUTO | RUNTIME 330 // chunk_size -> ScalarIntExpr 331 TYPE_PARSER(construct<OmpScheduleModifierType>( 332 "MONOTONIC" >> pure(OmpScheduleModifierType::ModType::Monotonic) || 333 "NONMONOTONIC" >> pure(OmpScheduleModifierType::ModType::Nonmonotonic) || 334 "SIMD" >> pure(OmpScheduleModifierType::ModType::Simd))) 335 336 TYPE_PARSER(construct<OmpScheduleModifier>(Parser<OmpScheduleModifierType>{}, 337 maybe("," >> Parser<OmpScheduleModifierType>{}) / ":")) 338 339 TYPE_PARSER(construct<OmpScheduleClause>(maybe(Parser<OmpScheduleModifier>{}), 340 "STATIC" >> pure(OmpScheduleClause::ScheduleType::Static) || 341 "DYNAMIC" >> pure(OmpScheduleClause::ScheduleType::Dynamic) || 342 "GUIDED" >> pure(OmpScheduleClause::ScheduleType::Guided) || 343 "AUTO" >> pure(OmpScheduleClause::ScheduleType::Auto) || 344 "RUNTIME" >> pure(OmpScheduleClause::ScheduleType::Runtime), 345 maybe("," >> scalarIntExpr))) 346 347 // device([ device-modifier :] scalar-integer-expression) 348 TYPE_PARSER(construct<OmpDeviceClause>( 349 maybe( 350 ("ANCESTOR" >> pure(OmpDeviceClause::DeviceModifier::Ancestor) || 351 "DEVICE_NUM" >> pure(OmpDeviceClause::DeviceModifier::Device_Num)) / 352 ":"), 353 scalarIntExpr)) 354 355 // device_type(any | host | nohost) 356 TYPE_PARSER(construct<OmpDeviceTypeClause>( 357 "ANY" >> pure(OmpDeviceTypeClause::Type::Any) || 358 "HOST" >> pure(OmpDeviceTypeClause::Type::Host) || 359 "NOHOST" >> pure(OmpDeviceTypeClause::Type::Nohost))) 360 361 // 2.12 IF (directive-name-modifier: scalar-logical-expr) 362 TYPE_PARSER(construct<OmpIfClause>( 363 maybe( 364 ("PARALLEL" >> pure(OmpIfClause::DirectiveNameModifier::Parallel) || 365 "SIMD" >> pure(OmpIfClause::DirectiveNameModifier::Simd) || 366 "TARGET ENTER DATA" >> 367 pure(OmpIfClause::DirectiveNameModifier::TargetEnterData) || 368 "TARGET EXIT DATA" >> 369 pure(OmpIfClause::DirectiveNameModifier::TargetExitData) || 370 "TARGET DATA" >> 371 pure(OmpIfClause::DirectiveNameModifier::TargetData) || 372 "TARGET UPDATE" >> 373 pure(OmpIfClause::DirectiveNameModifier::TargetUpdate) || 374 "TARGET" >> pure(OmpIfClause::DirectiveNameModifier::Target) || 375 "TASK"_id >> pure(OmpIfClause::DirectiveNameModifier::Task) || 376 "TASKLOOP" >> pure(OmpIfClause::DirectiveNameModifier::Taskloop) || 377 "TEAMS" >> pure(OmpIfClause::DirectiveNameModifier::Teams)) / 378 ":"), 379 scalarLogicalExpr)) 380 381 TYPE_PARSER(construct<OmpReductionClause>( 382 maybe( 383 ("INSCAN" >> pure(OmpReductionClause::ReductionModifier::Inscan) || 384 "TASK" >> pure(OmpReductionClause::ReductionModifier::Task) || 385 "DEFAULT" >> pure(OmpReductionClause::ReductionModifier::Default)) / 386 ","), 387 Parser<OmpReductionIdentifier>{} / ":", Parser<OmpObjectList>{})) 388 389 // OMP 5.0 2.19.5.6 IN_REDUCTION (reduction-identifier: variable-name-list) 390 TYPE_PARSER(construct<OmpInReductionClause>( 391 Parser<OmpReductionIdentifier>{} / ":", Parser<OmpObjectList>{})) 392 393 // OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list) 394 // OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier 395 // [, allocate-modifier] :] 396 // variable-name-list) 397 // allocate-modifier -> allocator | align 398 TYPE_PARSER(construct<OmpAllocateClause>( 399 maybe( 400 first( 401 construct<OmpAllocateClause::AllocateModifier>("ALLOCATOR" >> 402 construct<OmpAllocateClause::AllocateModifier::ComplexModifier>( 403 parenthesized(construct< 404 OmpAllocateClause::AllocateModifier::Allocator>( 405 scalarIntExpr)) / 406 ",", 407 "ALIGN" >> parenthesized(construct< 408 OmpAllocateClause::AllocateModifier::Align>( 409 scalarIntExpr)))), 410 construct<OmpAllocateClause::AllocateModifier>("ALLOCATOR" >> 411 parenthesized( 412 construct<OmpAllocateClause::AllocateModifier::Allocator>( 413 scalarIntExpr))), 414 construct<OmpAllocateClause::AllocateModifier>("ALIGN" >> 415 parenthesized( 416 construct<OmpAllocateClause::AllocateModifier::Align>( 417 scalarIntExpr))), 418 construct<OmpAllocateClause::AllocateModifier>( 419 construct<OmpAllocateClause::AllocateModifier::Allocator>( 420 scalarIntExpr))) / 421 ":"), 422 Parser<OmpObjectList>{})) 423 424 // iteration-offset -> +/- non-negative-constant-expr 425 TYPE_PARSER(construct<OmpIterationOffset>( 426 Parser<DefinedOperator>{}, scalarIntConstantExpr)) 427 428 // iteration -> iteration-variable [+/- nonnegative-scalar-integer-constant] 429 TYPE_PARSER(construct<OmpIteration>(name, maybe(Parser<OmpIterationOffset>{}))) 430 431 TYPE_PARSER(construct<OmpIterationVector>(nonemptyList(Parser<OmpIteration>{}))) 432 433 TYPE_PARSER(construct<OmpDoacross>( 434 construct<OmpDoacross>(construct<OmpDoacross::Sink>( 435 "SINK"_tok >> ":"_tok >> Parser<OmpIterationVector>{})) || 436 construct<OmpDoacross>(construct<OmpDoacross::Source>("SOURCE"_tok)))) 437 438 TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, 439 construct<OmpDependClause>( 440 construct<OmpDependClause>(construct<OmpDependClause::TaskDep>( 441 maybe(Parser<OmpIterator>{} / ","_tok), 442 Parser<OmpTaskDependenceType>{} / ":", Parser<OmpObjectList>{})) || 443 construct<OmpDependClause>(Parser<OmpDoacross>{}))) 444 445 TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US, 446 construct<OmpDoacrossClause>(Parser<OmpDoacross>{})) 447 448 TYPE_PARSER(construct<OmpFromClause::Expectation>( 449 "PRESENT" >> pure(OmpFromClause::Expectation::Present))) 450 451 template <typename MotionClause, bool CommasEverywhere> 452 static inline MotionClause makeMotionClause( 453 std::tuple<std::optional<std::list<typename MotionClause::Expectation>>, 454 std::optional<std::list<OmpIterator>>> &&mods, 455 OmpObjectList &&objs) { 456 auto &&[exp, iter] = std::move(mods); 457 return MotionClause( 458 std::move(exp), std::move(iter), std::move(objs), CommasEverywhere); 459 } 460 461 TYPE_PARSER(construct<OmpFromClause>( 462 applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, true>, 463 MotionModifiers(","_tok), Parser<OmpObjectList>{}) || 464 applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, false>, 465 MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{}))) 466 467 TYPE_PARSER(construct<OmpToClause>( 468 applyFunction<OmpToClause>(makeMotionClause<OmpToClause, true>, 469 MotionModifiers(","_tok), Parser<OmpObjectList>{}) || 470 applyFunction<OmpToClause>(makeMotionClause<OmpToClause, false>, 471 MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{}))) 472 473 TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US, 474 construct<OmpLinearClause>( 475 construct<OmpLinearClause>(construct<OmpLinearClause::WithModifier>( 476 Parser<OmpLinearModifier>{}, parenthesized(nonemptyList(name)), 477 maybe(":" >> scalarIntConstantExpr))) || 478 construct<OmpLinearClause>(construct<OmpLinearClause::WithoutModifier>( 479 nonemptyList(name), maybe(":" >> scalarIntConstantExpr))))) 480 481 // OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle) 482 TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{})) 483 484 // 2.8.1 ALIGNED (list: alignment) 485 TYPE_PARSER(construct<OmpAlignedClause>( 486 Parser<OmpObjectList>{}, maybe(":" >> scalarIntConstantExpr))) 487 488 TYPE_PARSER(construct<OmpUpdateClause>( 489 construct<OmpUpdateClause>(Parser<OmpDependenceType>{}) || 490 construct<OmpUpdateClause>(Parser<OmpTaskDependenceType>{}))) 491 492 // 2.9.5 ORDER ([order-modifier :]concurrent) 493 TYPE_PARSER(construct<OmpOrderModifier>( 494 "REPRODUCIBLE" >> pure(OmpOrderModifier::Kind::Reproducible)) || 495 construct<OmpOrderModifier>( 496 "UNCONSTRAINED" >> pure(OmpOrderModifier::Kind::Unconstrained))) 497 498 TYPE_PARSER(construct<OmpOrderClause>(maybe(Parser<OmpOrderModifier>{} / ":"), 499 "CONCURRENT" >> pure(OmpOrderClause::Type::Concurrent))) 500 501 // OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression) 502 TYPE_PARSER(construct<OmpGrainsizeClause>( 503 maybe("STRICT" >> pure(OmpGrainsizeClause::Prescriptiveness::Strict) / ":"), 504 scalarIntExpr)) 505 506 // OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression) 507 TYPE_PARSER(construct<OmpNumTasksClause>( 508 maybe("STRICT" >> pure(OmpNumTasksClause::Prescriptiveness::Strict) / ":"), 509 scalarIntExpr)) 510 511 TYPE_PARSER( 512 construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/")) 513 514 // OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list) 515 TYPE_PARSER(construct<OmpLastprivateClause>( 516 maybe("CONDITIONAL" >> 517 pure(OmpLastprivateClause::LastprivateModifier::Conditional) / ":"), 518 Parser<OmpObjectList>{})) 519 520 // OMP 5.2 11.7.1 BIND ( PARALLEL | TEAMS | THREAD ) 521 TYPE_PARSER(construct<OmpBindClause>( 522 "PARALLEL" >> pure(OmpBindClause::Type::Parallel) || 523 "TEAMS" >> pure(OmpBindClause::Type::Teams) || 524 "THREAD" >> pure(OmpBindClause::Type::Thread))) 525 526 TYPE_PARSER( 527 "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) || 528 "ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) || 529 "AFFINITY" >> construct<OmpClause>(construct<OmpClause::Affinity>( 530 parenthesized(Parser<OmpAffinityClause>{}))) || 531 "ALIGNED" >> construct<OmpClause>(construct<OmpClause::Aligned>( 532 parenthesized(Parser<OmpAlignedClause>{}))) || 533 "ALLOCATE" >> construct<OmpClause>(construct<OmpClause::Allocate>( 534 parenthesized(Parser<OmpAllocateClause>{}))) || 535 "ALLOCATOR" >> construct<OmpClause>(construct<OmpClause::Allocator>( 536 parenthesized(scalarIntExpr))) || 537 "ATOMIC_DEFAULT_MEM_ORDER" >> 538 construct<OmpClause>(construct<OmpClause::AtomicDefaultMemOrder>( 539 parenthesized(Parser<OmpAtomicDefaultMemOrderClause>{}))) || 540 "BIND" >> construct<OmpClause>(construct<OmpClause::Bind>( 541 parenthesized(Parser<OmpBindClause>{}))) || 542 "COLLAPSE" >> construct<OmpClause>(construct<OmpClause::Collapse>( 543 parenthesized(scalarIntConstantExpr))) || 544 "COPYIN" >> construct<OmpClause>(construct<OmpClause::Copyin>( 545 parenthesized(Parser<OmpObjectList>{}))) || 546 "COPYPRIVATE" >> construct<OmpClause>(construct<OmpClause::Copyprivate>( 547 (parenthesized(Parser<OmpObjectList>{})))) || 548 "DEFAULT"_id >> construct<OmpClause>(construct<OmpClause::Default>( 549 parenthesized(Parser<OmpDefaultClause>{}))) || 550 "DEFAULTMAP" >> construct<OmpClause>(construct<OmpClause::Defaultmap>( 551 parenthesized(Parser<OmpDefaultmapClause>{}))) || 552 "DEPEND" >> construct<OmpClause>(construct<OmpClause::Depend>( 553 parenthesized(Parser<OmpDependClause>{}))) || 554 "DESTROY" >> 555 construct<OmpClause>(construct<OmpClause::Destroy>(maybe(parenthesized( 556 construct<OmpDestroyClause>(Parser<OmpObject>{}))))) || 557 "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>( 558 parenthesized(Parser<OmpDeviceClause>{}))) || 559 "DEVICE_TYPE" >> construct<OmpClause>(construct<OmpClause::DeviceType>( 560 parenthesized(Parser<OmpDeviceTypeClause>{}))) || 561 "DIST_SCHEDULE" >> 562 construct<OmpClause>(construct<OmpClause::DistSchedule>( 563 parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) || 564 "DOACROSS" >> 565 construct<OmpClause>(parenthesized(Parser<OmpDoacrossClause>{})) || 566 "DYNAMIC_ALLOCATORS" >> 567 construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) || 568 "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>( 569 parenthesized(Parser<OmpObjectList>{}))) || 570 "EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>( 571 parenthesized(Parser<OmpObjectList>{}))) || 572 "FILTER" >> construct<OmpClause>(construct<OmpClause::Filter>( 573 parenthesized(scalarIntExpr))) || 574 "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>( 575 parenthesized(scalarLogicalExpr))) || 576 "FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>( 577 parenthesized(Parser<OmpObjectList>{}))) || 578 "FROM" >> construct<OmpClause>(construct<OmpClause::From>( 579 parenthesized(Parser<OmpFromClause>{}))) || 580 "FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) || 581 "GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>( 582 parenthesized(Parser<OmpGrainsizeClause>{}))) || 583 "HAS_DEVICE_ADDR" >> 584 construct<OmpClause>(construct<OmpClause::HasDeviceAddr>( 585 parenthesized(Parser<OmpObjectList>{}))) || 586 "HINT" >> construct<OmpClause>( 587 construct<OmpClause::Hint>(parenthesized(constantExpr))) || 588 "IF" >> construct<OmpClause>(construct<OmpClause::If>( 589 parenthesized(Parser<OmpIfClause>{}))) || 590 "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) || 591 "INCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Inclusive>( 592 parenthesized(Parser<OmpObjectList>{}))) || 593 "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>( 594 parenthesized(Parser<OmpObjectList>{}))) || 595 "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>( 596 parenthesized(Parser<OmpLastprivateClause>{}))) || 597 "LINEAR" >> construct<OmpClause>(construct<OmpClause::Linear>( 598 parenthesized(Parser<OmpLinearClause>{}))) || 599 "LINK" >> construct<OmpClause>(construct<OmpClause::Link>( 600 parenthesized(Parser<OmpObjectList>{}))) || 601 "MAP" >> construct<OmpClause>(construct<OmpClause::Map>( 602 parenthesized(Parser<OmpMapClause>{}))) || 603 "MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) || 604 "NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) || 605 "NONTEMPORAL" >> construct<OmpClause>(construct<OmpClause::Nontemporal>( 606 parenthesized(nonemptyList(name)))) || 607 "NOTINBRANCH" >> 608 construct<OmpClause>(construct<OmpClause::Notinbranch>()) || 609 "NOWAIT" >> construct<OmpClause>(construct<OmpClause::Nowait>()) || 610 "NUM_TASKS" >> construct<OmpClause>(construct<OmpClause::NumTasks>( 611 parenthesized(Parser<OmpNumTasksClause>{}))) || 612 "NUM_TEAMS" >> construct<OmpClause>(construct<OmpClause::NumTeams>( 613 parenthesized(scalarIntExpr))) || 614 "NUM_THREADS" >> construct<OmpClause>(construct<OmpClause::NumThreads>( 615 parenthesized(scalarIntExpr))) || 616 "ORDER" >> construct<OmpClause>(construct<OmpClause::Order>( 617 parenthesized(Parser<OmpOrderClause>{}))) || 618 "ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>( 619 maybe(parenthesized(scalarIntConstantExpr)))) || 620 "PARTIAL" >> construct<OmpClause>(construct<OmpClause::Partial>( 621 maybe(parenthesized(scalarIntConstantExpr)))) || 622 "PRIORITY" >> construct<OmpClause>(construct<OmpClause::Priority>( 623 parenthesized(scalarIntExpr))) || 624 "PRIVATE" >> construct<OmpClause>(construct<OmpClause::Private>( 625 parenthesized(Parser<OmpObjectList>{}))) || 626 "PROC_BIND" >> construct<OmpClause>(construct<OmpClause::ProcBind>( 627 parenthesized(Parser<OmpProcBindClause>{}))) || 628 "REDUCTION" >> construct<OmpClause>(construct<OmpClause::Reduction>( 629 parenthesized(Parser<OmpReductionClause>{}))) || 630 "IN_REDUCTION" >> construct<OmpClause>(construct<OmpClause::InReduction>( 631 parenthesized(Parser<OmpInReductionClause>{}))) || 632 "DETACH" >> construct<OmpClause>(construct<OmpClause::Detach>( 633 parenthesized(Parser<OmpDetachClause>{}))) || 634 "TASK_REDUCTION" >> 635 construct<OmpClause>(construct<OmpClause::TaskReduction>( 636 parenthesized(Parser<OmpReductionClause>{}))) || 637 "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()) || 638 "RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) || 639 "REVERSE_OFFLOAD" >> 640 construct<OmpClause>(construct<OmpClause::ReverseOffload>()) || 641 "SAFELEN" >> construct<OmpClause>(construct<OmpClause::Safelen>( 642 parenthesized(scalarIntConstantExpr))) || 643 "SCHEDULE" >> construct<OmpClause>(construct<OmpClause::Schedule>( 644 parenthesized(Parser<OmpScheduleClause>{}))) || 645 "SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) || 646 "SHARED" >> construct<OmpClause>(construct<OmpClause::Shared>( 647 parenthesized(Parser<OmpObjectList>{}))) || 648 "SIMD"_id >> construct<OmpClause>(construct<OmpClause::Simd>()) || 649 "SIMDLEN" >> construct<OmpClause>(construct<OmpClause::Simdlen>( 650 parenthesized(scalarIntConstantExpr))) || 651 "SIZES" >> construct<OmpClause>(construct<OmpClause::Sizes>( 652 parenthesized(nonemptyList(scalarIntExpr)))) || 653 "PERMUTATION" >> construct<OmpClause>(construct<OmpClause::Permutation>( 654 parenthesized(nonemptyList(scalarIntExpr)))) || 655 "THREADS" >> construct<OmpClause>(construct<OmpClause::Threads>()) || 656 "THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>( 657 parenthesized(scalarIntExpr))) || 658 "TO" >> construct<OmpClause>(construct<OmpClause::To>( 659 parenthesized(Parser<OmpToClause>{}))) || 660 "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>( 661 parenthesized(Parser<OmpObjectList>{}))) || 662 "USE_DEVICE_ADDR" >> 663 construct<OmpClause>(construct<OmpClause::UseDeviceAddr>( 664 parenthesized(Parser<OmpObjectList>{}))) || 665 "UNIFIED_ADDRESS" >> 666 construct<OmpClause>(construct<OmpClause::UnifiedAddress>()) || 667 "UNIFIED_SHARED_MEMORY" >> 668 construct<OmpClause>(construct<OmpClause::UnifiedSharedMemory>()) || 669 "UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>( 670 parenthesized(nonemptyList(name)))) || 671 "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()) || 672 "UPDATE" >> construct<OmpClause>(construct<OmpClause::Update>( 673 parenthesized(Parser<OmpUpdateClause>{})))) 674 675 // [Clause, [Clause], ...] 676 TYPE_PARSER(sourced(construct<OmpClauseList>( 677 many(maybe(","_tok) >> sourced(Parser<OmpClause>{}))))) 678 679 // 2.1 (variable | /common-block | array-sections) 680 TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{}))) 681 682 // Omp directives enclosing do loop 683 TYPE_PARSER(sourced(construct<OmpLoopDirective>(first( 684 "DISTRIBUTE PARALLEL DO SIMD" >> 685 pure(llvm::omp::Directive::OMPD_distribute_parallel_do_simd), 686 "DISTRIBUTE PARALLEL DO" >> 687 pure(llvm::omp::Directive::OMPD_distribute_parallel_do), 688 "DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_distribute_simd), 689 "DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_distribute), 690 "DO SIMD" >> pure(llvm::omp::Directive::OMPD_do_simd), 691 "DO" >> pure(llvm::omp::Directive::OMPD_do), 692 "LOOP" >> pure(llvm::omp::Directive::OMPD_loop), 693 "MASKED TASKLOOP SIMD" >> 694 pure(llvm::omp::Directive::OMPD_masked_taskloop_simd), 695 "MASKED TASKLOOP" >> pure(llvm::omp::Directive::OMPD_masked_taskloop), 696 "MASTER TASKLOOP SIMD" >> 697 pure(llvm::omp::Directive::OMPD_master_taskloop_simd), 698 "MASTER TASKLOOP" >> pure(llvm::omp::Directive::OMPD_master_taskloop), 699 "PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_do_simd), 700 "PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_parallel_do), 701 "PARALLEL MASKED TASKLOOP SIMD" >> 702 pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop_simd), 703 "PARALLEL MASKED TASKLOOP" >> 704 pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop), 705 "PARALLEL MASTER TASKLOOP SIMD" >> 706 pure(llvm::omp::Directive::OMPD_parallel_master_taskloop_simd), 707 "PARALLEL MASTER TASKLOOP" >> 708 pure(llvm::omp::Directive::OMPD_parallel_master_taskloop), 709 "SIMD" >> pure(llvm::omp::Directive::OMPD_simd), 710 "TARGET LOOP" >> pure(llvm::omp::Directive::OMPD_target_loop), 711 "TARGET PARALLEL DO SIMD" >> 712 pure(llvm::omp::Directive::OMPD_target_parallel_do_simd), 713 "TARGET PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_target_parallel_do), 714 "TARGET PARALLEL LOOP" >> 715 pure(llvm::omp::Directive::OMPD_target_parallel_loop), 716 "TARGET SIMD" >> pure(llvm::omp::Directive::OMPD_target_simd), 717 "TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD" >> 718 pure(llvm::omp::Directive:: 719 OMPD_target_teams_distribute_parallel_do_simd), 720 "TARGET TEAMS DISTRIBUTE PARALLEL DO" >> 721 pure(llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do), 722 "TARGET TEAMS DISTRIBUTE SIMD" >> 723 pure(llvm::omp::Directive::OMPD_target_teams_distribute_simd), 724 "TARGET TEAMS DISTRIBUTE" >> 725 pure(llvm::omp::Directive::OMPD_target_teams_distribute), 726 "TARGET TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_target_teams_loop), 727 "TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_taskloop_simd), 728 "TASKLOOP" >> pure(llvm::omp::Directive::OMPD_taskloop), 729 "TEAMS DISTRIBUTE PARALLEL DO SIMD" >> 730 pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd), 731 "TEAMS DISTRIBUTE PARALLEL DO" >> 732 pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do), 733 "TEAMS DISTRIBUTE SIMD" >> 734 pure(llvm::omp::Directive::OMPD_teams_distribute_simd), 735 "TEAMS DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_teams_distribute), 736 "TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_teams_loop), 737 "TILE" >> pure(llvm::omp::Directive::OMPD_tile), 738 "UNROLL" >> pure(llvm::omp::Directive::OMPD_unroll))))) 739 740 TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>( 741 sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{}))) 742 743 // 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP 744 TYPE_PARSER(sourced(construct<OmpCancelType>( 745 first("PARALLEL" >> pure(OmpCancelType::Type::Parallel), 746 "SECTIONS" >> pure(OmpCancelType::Type::Sections), 747 "DO" >> pure(OmpCancelType::Type::Do), 748 "TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup))))) 749 750 // 2.14.2 Cancellation Point construct 751 TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>( 752 verbatim("CANCELLATION POINT"_tok), Parser<OmpCancelType>{}))) 753 754 // 2.14.1 Cancel construct 755 TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(verbatim("CANCEL"_tok), 756 Parser<OmpCancelType>{}, maybe("IF" >> parenthesized(scalarLogicalExpr))))) 757 758 // 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0] 759 // memory-order-clause -> 760 // seq_cst 761 // acq_rel 762 // release 763 // acquire 764 // relaxed 765 TYPE_PARSER(sourced(construct<OmpMemoryOrderClause>( 766 sourced("SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) || 767 "ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) || 768 "RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) || 769 "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) || 770 "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()))))) 771 772 // 2.4 Requires construct [OpenMP 5.0] 773 // atomic-default-mem-order-clause -> 774 // seq_cst 775 // acq_rel 776 // relaxed 777 TYPE_PARSER(construct<OmpAtomicDefaultMemOrderClause>( 778 "SEQ_CST" >> pure(common::OmpAtomicDefaultMemOrderType::SeqCst) || 779 "ACQ_REL" >> pure(common::OmpAtomicDefaultMemOrderType::AcqRel) || 780 "RELAXED" >> pure(common::OmpAtomicDefaultMemOrderType::Relaxed))) 781 782 // 2.17.7 Atomic construct 783 // atomic-clause -> memory-order-clause | HINT(hint-expression) 784 TYPE_PARSER(sourced(construct<OmpAtomicClause>( 785 construct<OmpAtomicClause>(Parser<OmpMemoryOrderClause>{}) || 786 construct<OmpAtomicClause>("HINT" >> 787 sourced(construct<OmpClause>( 788 construct<OmpClause::Hint>(parenthesized(constantExpr)))))))) 789 790 // atomic-clause-list -> [atomic-clause, [atomic-clause], ...] 791 TYPE_PARSER(sourced(construct<OmpAtomicClauseList>( 792 many(maybe(","_tok) >> sourced(Parser<OmpAtomicClause>{}))))) 793 794 TYPE_PARSER(sourced(construct<OpenMPDepobjConstruct>(verbatim("DEPOBJ"_tok), 795 parenthesized(Parser<OmpObject>{}), sourced(Parser<OmpClause>{})))) 796 797 TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok), 798 many(maybe(","_tok) >> sourced(Parser<OmpMemoryOrderClause>{})), 799 maybe(parenthesized(Parser<OmpObjectList>{}))))) 800 801 // Simple Standalone Directives 802 TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first( 803 "BARRIER" >> pure(llvm::omp::Directive::OMPD_barrier), 804 "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered), 805 "SCAN" >> pure(llvm::omp::Directive::OMPD_scan), 806 "TARGET ENTER DATA" >> pure(llvm::omp::Directive::OMPD_target_enter_data), 807 "TARGET EXIT DATA" >> pure(llvm::omp::Directive::OMPD_target_exit_data), 808 "TARGET UPDATE" >> pure(llvm::omp::Directive::OMPD_target_update), 809 "TASKWAIT" >> pure(llvm::omp::Directive::OMPD_taskwait), 810 "TASKYIELD" >> pure(llvm::omp::Directive::OMPD_taskyield))))) 811 812 TYPE_PARSER(sourced(construct<OpenMPSimpleStandaloneConstruct>( 813 Parser<OmpSimpleStandaloneDirective>{}, Parser<OmpClauseList>{}))) 814 815 // Standalone Constructs 816 TYPE_PARSER( 817 sourced(construct<OpenMPStandaloneConstruct>( 818 Parser<OpenMPSimpleStandaloneConstruct>{}) || 819 construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) || 820 construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) || 821 construct<OpenMPStandaloneConstruct>( 822 Parser<OpenMPCancellationPointConstruct>{}) || 823 construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{})) / 824 endOfLine) 825 826 // Directives enclosing structured-block 827 TYPE_PARSER(construct<OmpBlockDirective>(first( 828 "MASKED" >> pure(llvm::omp::Directive::OMPD_masked), 829 "MASTER" >> pure(llvm::omp::Directive::OMPD_master), 830 "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered), 831 "PARALLEL MASKED" >> pure(llvm::omp::Directive::OMPD_parallel_masked), 832 "PARALLEL MASTER" >> pure(llvm::omp::Directive::OMPD_parallel_master), 833 "PARALLEL WORKSHARE" >> pure(llvm::omp::Directive::OMPD_parallel_workshare), 834 "PARALLEL" >> pure(llvm::omp::Directive::OMPD_parallel), 835 "SCOPE" >> pure(llvm::omp::Directive::OMPD_scope), 836 "SINGLE" >> pure(llvm::omp::Directive::OMPD_single), 837 "TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data), 838 "TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel), 839 "TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams), 840 "TARGET" >> pure(llvm::omp::Directive::OMPD_target), 841 "TASK"_id >> pure(llvm::omp::Directive::OMPD_task), 842 "TASKGROUP" >> pure(llvm::omp::Directive::OMPD_taskgroup), 843 "TEAMS" >> pure(llvm::omp::Directive::OMPD_teams), 844 "WORKSHARE" >> pure(llvm::omp::Directive::OMPD_workshare)))) 845 846 TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>( 847 sourced(Parser<OmpBlockDirective>{}), Parser<OmpClauseList>{}))) 848 849 TYPE_PARSER(construct<OmpReductionInitializerClause>( 850 "INITIALIZER" >> parenthesized("OMP_PRIV =" >> expr))) 851 852 // 2.16 Declare Reduction Construct 853 TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>( 854 verbatim("DECLARE REDUCTION"_tok), 855 "(" >> Parser<OmpReductionIdentifier>{} / ":", 856 nonemptyList(Parser<DeclarationTypeSpec>{}) / ":", 857 Parser<OmpReductionCombiner>{} / ")", 858 maybe(Parser<OmpReductionInitializerClause>{})))) 859 860 // declare-target with list 861 TYPE_PARSER(sourced(construct<OmpDeclareTargetWithList>( 862 parenthesized(Parser<OmpObjectList>{})))) 863 864 // declare-target with clause 865 TYPE_PARSER( 866 sourced(construct<OmpDeclareTargetWithClause>(Parser<OmpClauseList>{}))) 867 868 // declare-target-specifier 869 TYPE_PARSER( 870 construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithList>{}) || 871 construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithClause>{})) 872 873 // 2.10.6 Declare Target Construct 874 TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>( 875 verbatim("DECLARE TARGET"_tok), Parser<OmpDeclareTargetSpecifier>{}))) 876 877 // declare-mapper-specifier 878 TYPE_PARSER(construct<OmpDeclareMapperSpecifier>( 879 maybe(name / ":" / !":"_tok), typeSpec / "::", name)) 880 881 // OpenMP 5.2: 5.8.8 Declare Mapper Construct 882 TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>( 883 verbatim("DECLARE MAPPER"_tok), 884 "(" >> Parser<OmpDeclareMapperSpecifier>{} / ")", Parser<OmpClauseList>{}))) 885 886 TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) || 887 construct<OmpReductionCombiner>( 888 construct<OmpReductionCombiner::FunctionCombiner>( 889 construct<Call>(Parser<ProcedureDesignator>{}, 890 parenthesized(optionalList(actualArgSpec)))))) 891 892 // 2.17.7 atomic -> ATOMIC [clause [,]] atomic-clause [[,] clause] | 893 // ATOMIC [clause] 894 // clause -> memory-order-clause | HINT(hint-expression) 895 // memory-order-clause -> SEQ_CST | ACQ_REL | RELEASE | ACQUIRE | RELAXED 896 // atomic-clause -> READ | WRITE | UPDATE | CAPTURE 897 898 // OMP END ATOMIC 899 TYPE_PARSER(construct<OmpEndAtomic>(startOmpLine >> "END ATOMIC"_tok)) 900 901 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] READ [MEMORY-ORDER-CLAUSE-LIST] 902 TYPE_PARSER("ATOMIC" >> 903 sourced(construct<OmpAtomicRead>( 904 Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("READ"_tok), 905 Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt), 906 maybe(Parser<OmpEndAtomic>{} / endOmpLine)))) 907 908 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] CAPTURE [MEMORY-ORDER-CLAUSE-LIST] 909 TYPE_PARSER("ATOMIC" >> 910 sourced(construct<OmpAtomicCapture>( 911 Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("CAPTURE"_tok), 912 Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt), 913 statement(assignmentStmt), Parser<OmpEndAtomic>{} / endOmpLine))) 914 915 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST] 916 TYPE_PARSER("ATOMIC" >> 917 sourced(construct<OmpAtomicUpdate>( 918 Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("UPDATE"_tok), 919 Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt), 920 maybe(Parser<OmpEndAtomic>{} / endOmpLine)))) 921 922 // OMP ATOMIC [atomic-clause-list] 923 TYPE_PARSER(sourced(construct<OmpAtomic>(verbatim("ATOMIC"_tok), 924 Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt), 925 maybe(Parser<OmpEndAtomic>{} / endOmpLine)))) 926 927 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] WRITE [MEMORY-ORDER-CLAUSE-LIST] 928 TYPE_PARSER("ATOMIC" >> 929 sourced(construct<OmpAtomicWrite>( 930 Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("WRITE"_tok), 931 Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt), 932 maybe(Parser<OmpEndAtomic>{} / endOmpLine)))) 933 934 // Atomic Construct 935 TYPE_PARSER(construct<OpenMPAtomicConstruct>(Parser<OmpAtomicRead>{}) || 936 construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCapture>{}) || 937 construct<OpenMPAtomicConstruct>(Parser<OmpAtomicWrite>{}) || 938 construct<OpenMPAtomicConstruct>(Parser<OmpAtomicUpdate>{}) || 939 construct<OpenMPAtomicConstruct>(Parser<OmpAtomic>{})) 940 941 // 2.13.2 OMP CRITICAL 942 TYPE_PARSER(startOmpLine >> 943 sourced(construct<OmpEndCriticalDirective>( 944 verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) / 945 endOmpLine) 946 TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok), 947 maybe(parenthesized(name)), Parser<OmpClauseList>{})) / 948 endOmpLine) 949 950 TYPE_PARSER(construct<OpenMPCriticalConstruct>( 951 Parser<OmpCriticalDirective>{}, block, Parser<OmpEndCriticalDirective>{})) 952 953 // 2.11.3 Executable Allocate directive 954 TYPE_PARSER( 955 sourced(construct<OpenMPExecutableAllocate>(verbatim("ALLOCATE"_tok), 956 maybe(parenthesized(Parser<OmpObjectList>{})), Parser<OmpClauseList>{}, 957 maybe(nonemptyList(Parser<OpenMPDeclarativeAllocate>{})) / endOmpLine, 958 statement(allocateStmt)))) 959 960 // 6.7 Allocators construct [OpenMP 5.2] 961 // allocators-construct -> ALLOCATORS [allocate-clause [,]] 962 // allocate-stmt 963 // [omp-end-allocators-construct] 964 TYPE_PARSER(sourced(construct<OpenMPAllocatorsConstruct>( 965 verbatim("ALLOCATORS"_tok), Parser<OmpClauseList>{} / endOmpLine, 966 statement(allocateStmt), maybe(Parser<OmpEndAllocators>{} / endOmpLine)))) 967 968 TYPE_PARSER(construct<OmpEndAllocators>(startOmpLine >> "END ALLOCATORS"_tok)) 969 970 // 2.8.2 Declare Simd construct 971 TYPE_PARSER( 972 sourced(construct<OpenMPDeclareSimdConstruct>(verbatim("DECLARE SIMD"_tok), 973 maybe(parenthesized(name)), Parser<OmpClauseList>{}))) 974 975 // 2.4 Requires construct 976 TYPE_PARSER(sourced(construct<OpenMPRequiresConstruct>( 977 verbatim("REQUIRES"_tok), Parser<OmpClauseList>{}))) 978 979 // 2.15.2 Threadprivate directive 980 TYPE_PARSER(sourced(construct<OpenMPThreadprivate>( 981 verbatim("THREADPRIVATE"_tok), parenthesized(Parser<OmpObjectList>{})))) 982 983 // 2.11.3 Declarative Allocate directive 984 TYPE_PARSER( 985 sourced(construct<OpenMPDeclarativeAllocate>(verbatim("ALLOCATE"_tok), 986 parenthesized(Parser<OmpObjectList>{}), Parser<OmpClauseList>{})) / 987 lookAhead(endOmpLine / !statement(allocateStmt))) 988 989 // Declarative constructs 990 TYPE_PARSER(startOmpLine >> 991 withMessage("expected OpenMP construct"_err_en_US, 992 sourced(construct<OpenMPDeclarativeConstruct>( 993 Parser<OpenMPDeclareReductionConstruct>{}) || 994 construct<OpenMPDeclarativeConstruct>( 995 Parser<OpenMPDeclareMapperConstruct>{}) || 996 construct<OpenMPDeclarativeConstruct>( 997 Parser<OpenMPDeclareSimdConstruct>{}) || 998 construct<OpenMPDeclarativeConstruct>( 999 Parser<OpenMPDeclareTargetConstruct>{}) || 1000 construct<OpenMPDeclarativeConstruct>( 1001 Parser<OpenMPDeclarativeAllocate>{}) || 1002 construct<OpenMPDeclarativeConstruct>( 1003 Parser<OpenMPRequiresConstruct>{}) || 1004 construct<OpenMPDeclarativeConstruct>( 1005 Parser<OpenMPThreadprivate>{})) / 1006 endOmpLine)) 1007 1008 // Block Construct 1009 TYPE_PARSER(construct<OpenMPBlockConstruct>( 1010 Parser<OmpBeginBlockDirective>{} / endOmpLine, block, 1011 Parser<OmpEndBlockDirective>{} / endOmpLine)) 1012 1013 // OMP SECTIONS Directive 1014 TYPE_PARSER(construct<OmpSectionsDirective>(first( 1015 "SECTIONS" >> pure(llvm::omp::Directive::OMPD_sections), 1016 "PARALLEL SECTIONS" >> pure(llvm::omp::Directive::OMPD_parallel_sections)))) 1017 1018 // OMP BEGIN and END SECTIONS Directive 1019 TYPE_PARSER(sourced(construct<OmpBeginSectionsDirective>( 1020 sourced(Parser<OmpSectionsDirective>{}), Parser<OmpClauseList>{}))) 1021 TYPE_PARSER( 1022 startOmpLine >> sourced(construct<OmpEndSectionsDirective>( 1023 sourced("END"_tok >> Parser<OmpSectionsDirective>{}), 1024 Parser<OmpClauseList>{}))) 1025 1026 // OMP SECTION-BLOCK 1027 1028 TYPE_PARSER(construct<OpenMPSectionConstruct>(block)) 1029 1030 TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >> 1031 construct<OmpSectionBlocks>(nonemptySeparated( 1032 construct<OpenMPConstruct>(sourced(Parser<OpenMPSectionConstruct>{})), 1033 startOmpLine >> "SECTION"_tok / endOmpLine))) 1034 1035 // OMP SECTIONS (OpenMP 5.0 - 2.8.1), PARALLEL SECTIONS (OpenMP 5.0 - 2.13.3) 1036 TYPE_PARSER(construct<OpenMPSectionsConstruct>( 1037 Parser<OmpBeginSectionsDirective>{} / endOmpLine, 1038 Parser<OmpSectionBlocks>{}, Parser<OmpEndSectionsDirective>{} / endOmpLine)) 1039 1040 TYPE_CONTEXT_PARSER("OpenMP construct"_en_US, 1041 startOmpLine >> 1042 withMessage("expected OpenMP construct"_err_en_US, 1043 first(construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}), 1044 construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}), 1045 construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}), 1046 // OpenMPBlockConstruct is attempted before 1047 // OpenMPStandaloneConstruct to resolve !$OMP ORDERED 1048 construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}), 1049 construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}), 1050 construct<OpenMPConstruct>(Parser<OpenMPExecutableAllocate>{}), 1051 construct<OpenMPConstruct>(Parser<OpenMPAllocatorsConstruct>{}), 1052 construct<OpenMPConstruct>(Parser<OpenMPDeclarativeAllocate>{}), 1053 construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{})))) 1054 1055 // END OMP Block directives 1056 TYPE_PARSER( 1057 startOmpLine >> sourced(construct<OmpEndBlockDirective>( 1058 sourced("END"_tok >> Parser<OmpBlockDirective>{}), 1059 Parser<OmpClauseList>{}))) 1060 1061 // END OMP Loop directives 1062 TYPE_PARSER( 1063 startOmpLine >> sourced(construct<OmpEndLoopDirective>( 1064 sourced("END"_tok >> Parser<OmpLoopDirective>{}), 1065 Parser<OmpClauseList>{}))) 1066 1067 TYPE_PARSER(construct<OpenMPLoopConstruct>( 1068 Parser<OmpBeginLoopDirective>{} / endOmpLine)) 1069 } // namespace Fortran::parser 1070