xref: /llvm-project/flang/lib/Parser/openmp-parsers.cpp (revision 5c37b2a5eee49df2545a6455eec64fb4b105df40)
1 //===-- lib/Parser/openmp-parsers.cpp -------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // Top-level grammar specification for OpenMP.
10 // See OpenMP-4.5-grammar.txt for documentation.
11 
12 #include "basic-parsers.h"
13 #include "expr-parsers.h"
14 #include "misc-parsers.h"
15 #include "stmt-parser.h"
16 #include "token-parsers.h"
17 #include "type-parser-implementation.h"
18 #include "flang/Parser/parse-tree.h"
19 
20 // OpenMP Directives and Clauses
21 namespace Fortran::parser {
22 
23 constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok;
24 constexpr auto endOmpLine = space >> endOfLine;
25 
26 template <typename A> constexpr decltype(auto) verbatim(A x) {
27   return sourced(construct<Verbatim>(x));
28 }
29 
30 // OpenMP Clauses
31 // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
32 TYPE_PARSER(construct<OmpDefaultClause>(
33     "PRIVATE" >> pure(OmpDefaultClause::Type::Private) ||
34     "FIRSTPRIVATE" >> pure(OmpDefaultClause::Type::Firstprivate) ||
35     "SHARED" >> pure(OmpDefaultClause::Type::Shared) ||
36     "NONE" >> pure(OmpDefaultClause::Type::None)))
37 
38 // 2.5 PROC_BIND (MASTER | CLOSE | SPREAD)
39 TYPE_PARSER(construct<OmpProcBindClause>(
40     "CLOSE" >> pure(OmpProcBindClause::Type::Close) ||
41     "MASTER" >> pure(OmpProcBindClause::Type::Master) ||
42     "SPREAD" >> pure(OmpProcBindClause::Type::Spread)))
43 
44 // 2.15.5.1 MAP ([ [ALWAYS[,]] map-type : ] variable-name-list)
45 //          map-type -> TO | FROM | TOFROM | ALLOC | RELEASE | DELETE
46 TYPE_PARSER(construct<OmpMapType>(
47     maybe("ALWAYS" >> construct<OmpMapType::Always>() / maybe(","_tok)),
48     ("TO"_id >> pure(OmpMapType::Type::To) ||
49         "FROM" >> pure(OmpMapType::Type::From) ||
50         "TOFROM" >> pure(OmpMapType::Type::Tofrom) ||
51         "ALLOC" >> pure(OmpMapType::Type::Alloc) ||
52         "RELEASE" >> pure(OmpMapType::Type::Release) ||
53         "DELETE" >> pure(OmpMapType::Type::Delete)) /
54         ":"))
55 
56 TYPE_PARSER(construct<OmpMapClause>(
57     maybe(Parser<OmpMapType>{}), Parser<OmpObjectList>{}))
58 
59 // 2.15.5.2 defaultmap -> DEFAULTMAP (TOFROM:SCALAR)
60 TYPE_PARSER(construct<OmpDefaultmapClause>(
61     construct<OmpDefaultmapClause::ImplicitBehavior>(
62         "TOFROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::Tofrom)),
63     maybe(":" >> construct<OmpDefaultmapClause::VariableCategory>("SCALAR" >>
64                      pure(OmpDefaultmapClause::VariableCategory::Scalar)))))
65 
66 // 2.7.1 SCHEDULE ([modifier1 [, modifier2]:]kind[, chunk_size])
67 //       Modifier ->  MONITONIC | NONMONOTONIC | SIMD
68 //       kind -> STATIC | DYNAMIC | GUIDED | AUTO | RUNTIME
69 //       chunk_size -> ScalarIntExpr
70 TYPE_PARSER(construct<OmpScheduleModifierType>(
71     "MONOTONIC" >> pure(OmpScheduleModifierType::ModType::Monotonic) ||
72     "NONMONOTONIC" >> pure(OmpScheduleModifierType::ModType::Nonmonotonic) ||
73     "SIMD" >> pure(OmpScheduleModifierType::ModType::Simd)))
74 
75 TYPE_PARSER(construct<OmpScheduleModifier>(Parser<OmpScheduleModifierType>{},
76     maybe("," >> Parser<OmpScheduleModifierType>{}) / ":"))
77 
78 TYPE_PARSER(construct<OmpScheduleClause>(maybe(Parser<OmpScheduleModifier>{}),
79     "STATIC" >> pure(OmpScheduleClause::ScheduleType::Static) ||
80         "DYNAMIC" >> pure(OmpScheduleClause::ScheduleType::Dynamic) ||
81         "GUIDED" >> pure(OmpScheduleClause::ScheduleType::Guided) ||
82         "AUTO" >> pure(OmpScheduleClause::ScheduleType::Auto) ||
83         "RUNTIME" >> pure(OmpScheduleClause::ScheduleType::Runtime),
84     maybe("," >> scalarIntExpr)))
85 
86 // 2.12 IF (directive-name-modifier: scalar-logical-expr)
87 TYPE_PARSER(construct<OmpIfClause>(
88     maybe(
89         ("PARALLEL" >> pure(OmpIfClause::DirectiveNameModifier::Parallel) ||
90             "TARGET ENTER DATA" >>
91                 pure(OmpIfClause::DirectiveNameModifier::TargetEnterData) ||
92             "TARGET EXIT DATA" >>
93                 pure(OmpIfClause::DirectiveNameModifier::TargetExitData) ||
94             "TARGET DATA" >>
95                 pure(OmpIfClause::DirectiveNameModifier::TargetData) ||
96             "TARGET UPDATE" >>
97                 pure(OmpIfClause::DirectiveNameModifier::TargetUpdate) ||
98             "TARGET" >> pure(OmpIfClause::DirectiveNameModifier::Target) ||
99             "TASK"_id >> pure(OmpIfClause::DirectiveNameModifier::Task) ||
100             "TASKLOOP" >> pure(OmpIfClause::DirectiveNameModifier::Taskloop)) /
101         ":"),
102     scalarLogicalExpr))
103 
104 // 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
105 TYPE_PARSER(construct<OmpReductionOperator>(Parser<DefinedOperator>{}) ||
106     construct<OmpReductionOperator>(Parser<ProcedureDesignator>{}))
107 
108 TYPE_PARSER(construct<OmpReductionClause>(
109     Parser<OmpReductionOperator>{} / ":", nonemptyList(designator)))
110 
111 // 2.13.9 DEPEND (SOURCE | SINK : vec | (IN | OUT | INOUT) : list
112 TYPE_PARSER(construct<OmpDependSinkVecLength>(
113     Parser<DefinedOperator>{}, scalarIntConstantExpr))
114 
115 TYPE_PARSER(
116     construct<OmpDependSinkVec>(name, maybe(Parser<OmpDependSinkVecLength>{})))
117 
118 TYPE_PARSER(
119     construct<OmpDependenceType>("IN"_id >> pure(OmpDependenceType::Type::In) ||
120         "INOUT" >> pure(OmpDependenceType::Type::Inout) ||
121         "OUT" >> pure(OmpDependenceType::Type::Out)))
122 
123 TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
124     construct<OmpDependClause>(construct<OmpDependClause::Sink>(
125         "SINK :" >> nonemptyList(Parser<OmpDependSinkVec>{}))) ||
126         construct<OmpDependClause>(
127             construct<OmpDependClause::Source>("SOURCE"_tok)) ||
128         construct<OmpDependClause>(construct<OmpDependClause::InOut>(
129             Parser<OmpDependenceType>{}, ":" >> nonemptyList(designator))))
130 
131 // 2.15.3.7 LINEAR (linear-list: linear-step)
132 //          linear-list -> list | modifier(list)
133 //          linear-modifier -> REF | VAL | UVAL
134 TYPE_PARSER(
135     construct<OmpLinearModifier>("REF" >> pure(OmpLinearModifier::Type::Ref) ||
136         "VAL" >> pure(OmpLinearModifier::Type::Val) ||
137         "UVAL" >> pure(OmpLinearModifier::Type::Uval)))
138 
139 TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US,
140     construct<OmpLinearClause>(
141         construct<OmpLinearClause>(construct<OmpLinearClause::WithModifier>(
142             Parser<OmpLinearModifier>{}, parenthesized(nonemptyList(name)),
143             maybe(":" >> scalarIntConstantExpr))) ||
144         construct<OmpLinearClause>(construct<OmpLinearClause::WithoutModifier>(
145             nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))))
146 
147 // 2.8.1 ALIGNED (list: alignment)
148 TYPE_PARSER(construct<OmpAlignedClause>(
149     nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))
150 
151 TYPE_PARSER(
152     construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/"))
153 
154 TYPE_PARSER("ALIGNED" >>
155         construct<OmpClause>(parenthesized(Parser<OmpAlignedClause>{})) ||
156     "COLLAPSE" >> construct<OmpClause>(construct<OmpClause::Collapse>(
157                       parenthesized(scalarIntConstantExpr))) ||
158     "COPYIN" >> construct<OmpClause>(construct<OmpClause::Copyin>(
159                     parenthesized(Parser<OmpObjectList>{}))) ||
160     "COPYPRIVATE" >> construct<OmpClause>(construct<OmpClause::Copyprivate>(
161                          (parenthesized(Parser<OmpObjectList>{})))) ||
162     "DEFAULT"_id >>
163         construct<OmpClause>(parenthesized(Parser<OmpDefaultClause>{})) ||
164     "DEFAULTMAP" >>
165         construct<OmpClause>(parenthesized(Parser<OmpDefaultmapClause>{})) ||
166     "DEPEND" >>
167         construct<OmpClause>(parenthesized(Parser<OmpDependClause>{})) ||
168     "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
169                     parenthesized(scalarIntExpr))) ||
170     "DIST_SCHEDULE" >>
171         construct<OmpClause>(construct<OmpClause::DistSchedule>(
172             parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||
173     "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
174                    parenthesized(scalarLogicalExpr))) ||
175     "FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
176                           parenthesized(Parser<OmpObjectList>{}))) ||
177     "FROM" >> construct<OmpClause>(construct<OmpClause::From>(
178                   parenthesized(Parser<OmpObjectList>{}))) ||
179     "GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
180                        parenthesized(scalarIntExpr))) ||
181     "IF" >> construct<OmpClause>(parenthesized(Parser<OmpIfClause>{})) ||
182     "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
183     "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
184                            parenthesized(nonemptyList(name)))) ||
185     "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
186                          parenthesized(Parser<OmpObjectList>{}))) ||
187     "LINEAR" >>
188         construct<OmpClause>(parenthesized(Parser<OmpLinearClause>{})) ||
189     "LINK" >> construct<OmpClause>(construct<OmpClause::Link>(
190                   parenthesized(Parser<OmpObjectList>{}))) ||
191     "MAP" >> construct<OmpClause>(parenthesized(Parser<OmpMapClause>{})) ||
192     "MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) ||
193     "NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) ||
194     "NOTINBRANCH" >>
195         construct<OmpClause>(construct<OmpClause::Notinbranch>()) ||
196     "NOWAIT" >> construct<OmpClause>(construct<OmpNowait>()) ||
197     "NUM_TASKS" >> construct<OmpClause>(construct<OmpClause::NumTasks>(
198                        parenthesized(scalarIntExpr))) ||
199     "NUM_TEAMS" >> construct<OmpClause>(construct<OmpClause::NumTeams>(
200                        parenthesized(scalarIntExpr))) ||
201     "NUM_THREADS" >> construct<OmpClause>(construct<OmpClause::NumThreads>(
202                          parenthesized(scalarIntExpr))) ||
203     "ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>(
204                      maybe(parenthesized(scalarIntConstantExpr)))) ||
205     "PRIORITY" >> construct<OmpClause>(construct<OmpClause::Priority>(
206                       parenthesized(scalarIntExpr))) ||
207     "PRIVATE" >> construct<OmpClause>(construct<OmpClause::Private>(
208                      parenthesized(Parser<OmpObjectList>{}))) ||
209     "PROC_BIND" >>
210         construct<OmpClause>(parenthesized(Parser<OmpProcBindClause>{})) ||
211     "REDUCTION" >>
212         construct<OmpClause>(parenthesized(Parser<OmpReductionClause>{})) ||
213     "SAFELEN" >> construct<OmpClause>(construct<OmpClause::Safelen>(
214                      parenthesized(scalarIntConstantExpr))) ||
215     "SCHEDULE" >>
216         construct<OmpClause>(parenthesized(Parser<OmpScheduleClause>{})) ||
217     "SHARED" >> construct<OmpClause>(construct<OmpClause::Shared>(
218                     parenthesized(Parser<OmpObjectList>{}))) ||
219     "SIMD"_id >> construct<OmpClause>(construct<OmpClause::Simd>()) ||
220     "SIMDLEN" >> construct<OmpClause>(construct<OmpClause::Simdlen>(
221                      parenthesized(scalarIntConstantExpr))) ||
222     "THREADS" >> construct<OmpClause>(construct<OmpClause::Threads>()) ||
223     "THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
224                           parenthesized(scalarIntExpr))) ||
225     "TO" >> construct<OmpClause>(construct<OmpClause::To>(
226                 parenthesized(Parser<OmpObjectList>{}))) ||
227     "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
228                             parenthesized(nonemptyList(name)))) ||
229     "UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>(
230                      parenthesized(nonemptyList(name)))) ||
231     "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()))
232 
233 // [Clause, [Clause], ...]
234 TYPE_PARSER(sourced(construct<OmpClauseList>(
235     many(maybe(","_tok) >> sourced(Parser<OmpClause>{})))))
236 
237 // 2.1 (variable | /common-block | array-sections)
238 TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{})))
239 
240 // Omp directives enclosing do loop
241 TYPE_PARSER(sourced(construct<OmpLoopDirective>(first(
242     "DISTRIBUTE PARALLEL DO SIMD" >>
243         pure(OmpLoopDirective::Directive::DistributeParallelDoSimd),
244     "DISTRIBUTE PARALLEL DO" >>
245         pure(OmpLoopDirective::Directive::DistributeParallelDo),
246 
247     "DISTRIBUTE SIMD" >> pure(OmpLoopDirective::Directive::DistributeSimd),
248 
249     "DISTRIBUTE" >> pure(OmpLoopDirective::Directive::Distribute),
250 
251     "DO SIMD" >> pure(OmpLoopDirective::Directive::DoSimd),
252     "DO" >> pure(OmpLoopDirective::Directive::Do),
253     "PARALLEL DO SIMD" >> pure(OmpLoopDirective::Directive::ParallelDoSimd),
254 
255     "PARALLEL DO" >> pure(OmpLoopDirective::Directive::ParallelDo),
256 
257     "SIMD" >> pure(OmpLoopDirective::Directive::Simd),
258     "TARGET PARALLEL DO SIMD" >>
259         pure(OmpLoopDirective::Directive::TargetParallelDoSimd),
260     "TARGET PARALLEL DO" >> pure(OmpLoopDirective::Directive::TargetParallelDo),
261 
262     "TARGET SIMD" >> pure(OmpLoopDirective::Directive::TargetSimd),
263     "TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
264         pure(OmpLoopDirective::Directive::TargetTeamsDistributeParallelDoSimd),
265     "TARGET TEAMS DISTRIBUTE PARALLEL DO" >>
266         pure(OmpLoopDirective::Directive::TargetTeamsDistributeParallelDo),
267     "TARGET TEAMS DISTRIBUTE SIMD" >>
268         pure(OmpLoopDirective::Directive::TargetTeamsDistributeSimd),
269     "TARGET TEAMS DISTRIBUTE" >>
270         pure(OmpLoopDirective::Directive::TargetTeamsDistribute),
271 
272     "TASKLOOP SIMD" >> pure(OmpLoopDirective::Directive::TaskloopSimd),
273 
274     "TASKLOOP" >> pure(OmpLoopDirective::Directive::Taskloop),
275     "TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
276         pure(OmpLoopDirective::Directive::TeamsDistributeParallelDoSimd),
277     "TEAMS DISTRIBUTE PARALLEL DO" >>
278         pure(OmpLoopDirective::Directive::TeamsDistributeParallelDo),
279     "TEAMS DISTRIBUTE SIMD" >>
280         pure(OmpLoopDirective::Directive::TeamsDistributeSimd),
281     "TEAMS DISTRIBUTE" >> pure(OmpLoopDirective::Directive::TeamsDistribute)))))
282 
283 TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>(
284     sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{})))
285 
286 // 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP
287 TYPE_PARSER(sourced(construct<OmpCancelType>(
288     first("PARALLEL" >> pure(OmpCancelType::Type::Parallel),
289         "SECTIONS" >> pure(OmpCancelType::Type::Sections),
290         "DO" >> pure(OmpCancelType::Type::Do),
291         "TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup)))))
292 
293 // 2.14.2 Cancellation Point construct
294 TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>(
295     verbatim("CANCELLATION POINT"_tok), Parser<OmpCancelType>{})))
296 
297 // 2.14.1 Cancel construct
298 TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(verbatim("CANCEL"_tok),
299     Parser<OmpCancelType>{}, maybe("IF" >> parenthesized(scalarLogicalExpr)))))
300 
301 // 2.13.7 Flush construct
302 TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(
303     verbatim("FLUSH"_tok), maybe(parenthesized(Parser<OmpObjectList>{})))))
304 
305 // Simple Standalone Directives
306 TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
307     "BARRIER" >> pure(OmpSimpleStandaloneDirective::Directive::Barrier),
308     "ORDERED" >> pure(OmpSimpleStandaloneDirective::Directive::Ordered),
309     "TARGET ENTER DATA" >>
310         pure(OmpSimpleStandaloneDirective::Directive::TargetEnterData),
311     "TARGET EXIT DATA" >>
312         pure(OmpSimpleStandaloneDirective::Directive::TargetExitData),
313     "TARGET UPDATE" >>
314         pure(OmpSimpleStandaloneDirective::Directive::TargetUpdate),
315     "TASKWAIT" >> pure(OmpSimpleStandaloneDirective::Directive::Taskwait),
316     "TASKYIELD" >> pure(OmpSimpleStandaloneDirective::Directive::Taskyield)))))
317 
318 TYPE_PARSER(sourced(construct<OpenMPSimpleStandaloneConstruct>(
319     Parser<OmpSimpleStandaloneDirective>{}, Parser<OmpClauseList>{})))
320 
321 // Standalone Constructs
322 TYPE_PARSER(
323     sourced(construct<OpenMPStandaloneConstruct>(
324                 Parser<OpenMPSimpleStandaloneConstruct>{}) ||
325         construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
326         construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
327         construct<OpenMPStandaloneConstruct>(
328             Parser<OpenMPCancellationPointConstruct>{})) /
329     endOfLine)
330 
331 // Directives enclosing structured-block
332 TYPE_PARSER(construct<OmpBlockDirective>(
333     first("MASTER" >> pure(OmpBlockDirective::Directive::Master),
334         "ORDERED" >> pure(OmpBlockDirective::Directive::Ordered),
335         "PARALLEL WORKSHARE" >>
336             pure(OmpBlockDirective::Directive::ParallelWorkshare),
337         "PARALLEL" >> pure(OmpBlockDirective::Directive::Parallel),
338         "SINGLE" >> pure(OmpBlockDirective::Directive::Single),
339         "TARGET DATA" >> pure(OmpBlockDirective::Directive::TargetData),
340         "TARGET PARALLEL" >> pure(OmpBlockDirective::Directive::TargetParallel),
341         "TARGET TEAMS" >> pure(OmpBlockDirective::Directive::TargetTeams),
342         "TARGET" >> pure(OmpBlockDirective::Directive::Target),
343         "TASK"_id >> pure(OmpBlockDirective::Directive::Task),
344         "TASKGROUP" >> pure(OmpBlockDirective::Directive::Taskgroup),
345         "TEAMS" >> pure(OmpBlockDirective::Directive::Teams),
346         "WORKSHARE" >> pure(OmpBlockDirective::Directive::Workshare))))
347 
348 TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>(
349     sourced(Parser<OmpBlockDirective>{}), Parser<OmpClauseList>{})))
350 
351 TYPE_PARSER(construct<OmpReductionInitializerClause>(
352     "INITIALIZER" >> parenthesized("OMP_PRIV =" >> expr)))
353 
354 // 2.16 Declare Reduction Construct
355 TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
356     verbatim("DECLARE REDUCTION"_tok),
357     "(" >> Parser<OmpReductionOperator>{} / ":",
358     nonemptyList(Parser<DeclarationTypeSpec>{}) / ":",
359     Parser<OmpReductionCombiner>{} / ")",
360     maybe(Parser<OmpReductionInitializerClause>{}))))
361 
362 // declare-target with list
363 TYPE_PARSER(sourced(construct<OmpDeclareTargetWithList>(
364     parenthesized(Parser<OmpObjectList>{}))))
365 
366 // declare-target with clause
367 TYPE_PARSER(
368     sourced(construct<OmpDeclareTargetWithClause>(Parser<OmpClauseList>{})))
369 
370 // declare-target-specifier
371 TYPE_PARSER(
372     construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithList>{}) ||
373     construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithClause>{}))
374 
375 // 2.10.6 Declare Target Construct
376 TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
377     verbatim("DECLARE TARGET"_tok), Parser<OmpDeclareTargetSpecifier>{})))
378 
379 TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) ||
380     construct<OmpReductionCombiner>(
381         construct<OmpReductionCombiner::FunctionCombiner>(
382             construct<Call>(Parser<ProcedureDesignator>{},
383                 parenthesized(optionalList(actualArgSpec))))))
384 
385 // 2.13.6 ATOMIC [seq_cst[,]] atomic-clause [[,]seq_cst] | ATOMIC [seq_cst]
386 //        atomic-clause -> READ | WRITE | UPDATE | CAPTURE
387 
388 // OMP END ATOMIC
389 TYPE_PARSER(construct<OmpEndAtomic>(startOmpLine >> "END ATOMIC"_tok))
390 
391 // ATOMIC Memory related clause
392 TYPE_PARSER(sourced(construct<OmpMemoryClause>(
393     "SEQ_CST" >> pure(OmpMemoryClause::MemoryOrder::SeqCst))))
394 
395 // ATOMIC Memory Clause List
396 TYPE_PARSER(construct<OmpMemoryClauseList>(
397     many(maybe(","_tok) >> Parser<OmpMemoryClause>{})))
398 
399 TYPE_PARSER(construct<OmpMemoryClausePostList>(
400     many(maybe(","_tok) >> Parser<OmpMemoryClause>{})))
401 
402 // OMP [SEQ_CST] ATOMIC READ [SEQ_CST]
403 TYPE_PARSER("ATOMIC" >>
404     construct<OmpAtomicRead>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
405         verbatim("READ"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
406         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
407 
408 // OMP ATOMIC [SEQ_CST] CAPTURE [SEQ_CST]
409 TYPE_PARSER("ATOMIC" >>
410     construct<OmpAtomicCapture>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
411         verbatim("CAPTURE"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
412         statement(assignmentStmt), statement(assignmentStmt),
413         Parser<OmpEndAtomic>{} / endOmpLine))
414 
415 // OMP ATOMIC [SEQ_CST] UPDATE [SEQ_CST]
416 TYPE_PARSER("ATOMIC" >>
417     construct<OmpAtomicUpdate>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
418         verbatim("UPDATE"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
419         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
420 
421 // OMP ATOMIC [SEQ_CST]
422 TYPE_PARSER(construct<OmpAtomic>(verbatim("ATOMIC"_tok),
423     Parser<OmpMemoryClauseList>{} / endOmpLine, statement(assignmentStmt),
424     maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
425 
426 // ATOMIC [SEQ_CST] WRITE [SEQ_CST]
427 TYPE_PARSER("ATOMIC" >>
428     construct<OmpAtomicWrite>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
429         verbatim("WRITE"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
430         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
431 
432 // Atomic Construct
433 TYPE_PARSER(construct<OpenMPAtomicConstruct>(Parser<OmpAtomicRead>{}) ||
434     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCapture>{}) ||
435     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicWrite>{}) ||
436     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicUpdate>{}) ||
437     construct<OpenMPAtomicConstruct>(Parser<OmpAtomic>{}))
438 
439 // 2.13.2 OMP CRITICAL
440 TYPE_PARSER(startOmpLine >>
441     sourced(construct<OmpEndCriticalDirective>(
442         verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) /
443         endOmpLine)
444 TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok),
445                 maybe(parenthesized(name)),
446                 maybe("HINT" >> construct<OmpCriticalDirective::Hint>(
447                                     parenthesized(constantExpr))))) /
448     endOmpLine)
449 
450 TYPE_PARSER(construct<OpenMPCriticalConstruct>(
451     Parser<OmpCriticalDirective>{}, block, Parser<OmpEndCriticalDirective>{}))
452 
453 // 2.8.2 Declare Simd construct
454 TYPE_PARSER(
455     sourced(construct<OpenMPDeclareSimdConstruct>(verbatim("DECLARE SIMD"_tok),
456         maybe(parenthesized(name)), Parser<OmpClauseList>{})))
457 
458 // 2.15.2 Threadprivate directive
459 TYPE_PARSER(sourced(construct<OpenMPThreadprivate>(
460     verbatim("THREADPRIVATE"_tok), parenthesized(Parser<OmpObjectList>{}))))
461 
462 // Declarative constructs
463 TYPE_PARSER(startOmpLine >>
464     sourced(construct<OpenMPDeclarativeConstruct>(
465                 Parser<OpenMPDeclareReductionConstruct>{}) ||
466         construct<OpenMPDeclarativeConstruct>(
467             Parser<OpenMPDeclareSimdConstruct>{}) ||
468         construct<OpenMPDeclarativeConstruct>(
469             Parser<OpenMPDeclareTargetConstruct>{}) ||
470         construct<OpenMPDeclarativeConstruct>(Parser<OpenMPThreadprivate>{})) /
471         endOmpLine)
472 
473 // Block Construct
474 TYPE_PARSER(construct<OpenMPBlockConstruct>(
475     Parser<OmpBeginBlockDirective>{} / endOmpLine, block,
476     Parser<OmpEndBlockDirective>{} / endOmpLine))
477 
478 // OMP SECTIONS Directive
479 TYPE_PARSER(construct<OmpSectionsDirective>(
480     first("SECTIONS" >> pure(OmpSectionsDirective::Directive::Sections),
481         "PARALLEL SECTIONS" >>
482             pure(OmpSectionsDirective::Directive::ParallelSections))))
483 
484 // OMP BEGIN and END SECTIONS Directive
485 TYPE_PARSER(sourced(construct<OmpBeginSectionsDirective>(
486     sourced(Parser<OmpSectionsDirective>{}), Parser<OmpClauseList>{})))
487 TYPE_PARSER(
488     startOmpLine >> sourced(construct<OmpEndSectionsDirective>(
489                         sourced("END"_tok >> Parser<OmpSectionsDirective>{}),
490                         Parser<OmpClauseList>{})))
491 
492 // OMP SECTION-BLOCK
493 TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >>
494     construct<OmpSectionBlocks>(
495         nonemptySeparated(block, startOmpLine >> "SECTION"_tok / endOmpLine)))
496 
497 // OMP SECTIONS (2.7.2), PARALLEL SECTIONS (2.11.2)
498 TYPE_PARSER(construct<OpenMPSectionsConstruct>(
499     Parser<OmpBeginSectionsDirective>{} / endOmpLine,
500     Parser<OmpSectionBlocks>{}, Parser<OmpEndSectionsDirective>{} / endOmpLine))
501 
502 TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
503     startOmpLine >>
504         first(construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}),
505             construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}),
506             construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}),
507             // OpenMPBlockConstruct is attempted before
508             // OpenMPStandaloneConstruct to resolve !$OMP ORDERED
509             construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}),
510             construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}),
511             construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{})))
512 
513 // END OMP Block directives
514 TYPE_PARSER(
515     startOmpLine >> sourced(construct<OmpEndBlockDirective>(
516                         sourced("END"_tok >> Parser<OmpBlockDirective>{}),
517                         Parser<OmpClauseList>{})))
518 
519 // END OMP Loop directives
520 TYPE_PARSER(
521     startOmpLine >> sourced(construct<OmpEndLoopDirective>(
522                         sourced("END"_tok >> Parser<OmpLoopDirective>{}),
523                         Parser<OmpClauseList>{})))
524 
525 TYPE_PARSER(construct<OpenMPLoopConstruct>(
526     Parser<OmpBeginLoopDirective>{} / endOmpLine))
527 } // namespace Fortran::parser
528