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