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