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