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