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