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