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