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 // OpenMP Clauses
27 // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
28 TYPE_PARSER(construct<OmpDefaultClause>(
29     "PRIVATE" >> pure(OmpDefaultClause::Type::Private) ||
30     "FIRSTPRIVATE" >> pure(OmpDefaultClause::Type::Firstprivate) ||
31     "SHARED" >> pure(OmpDefaultClause::Type::Shared) ||
32     "NONE" >> pure(OmpDefaultClause::Type::None)))
33 
34 // 2.5 PROC_BIND (MASTER | CLOSE | SPREAD)
35 TYPE_PARSER(construct<OmpProcBindClause>(
36     "CLOSE" >> pure(OmpProcBindClause::Type::Close) ||
37     "MASTER" >> pure(OmpProcBindClause::Type::Master) ||
38     "SPREAD" >> pure(OmpProcBindClause::Type::Spread)))
39 
40 // 2.15.5.1 MAP ([ [ALWAYS[,]] map-type : ] variable-name-list)
41 //          map-type -> TO | FROM | TOFROM | ALLOC | RELEASE | DELETE
42 TYPE_PARSER(construct<OmpMapType>(
43     maybe("ALWAYS" >> construct<OmpMapType::Always>() / maybe(","_tok)),
44     ("TO"_id >> pure(OmpMapType::Type::To) ||
45         "FROM" >> pure(OmpMapType::Type::From) ||
46         "TOFROM" >> pure(OmpMapType::Type::Tofrom) ||
47         "ALLOC" >> pure(OmpMapType::Type::Alloc) ||
48         "RELEASE" >> pure(OmpMapType::Type::Release) ||
49         "DELETE" >> pure(OmpMapType::Type::Delete)) /
50         ":"))
51 
52 TYPE_PARSER(construct<OmpMapClause>(
53     maybe(Parser<OmpMapType>{}), Parser<OmpObjectList>{}))
54 
55 // 2.15.5.2 defaultmap -> DEFAULTMAP (TOFROM:SCALAR)
56 TYPE_PARSER(construct<OmpDefaultmapClause>(
57     construct<OmpDefaultmapClause::ImplicitBehavior>(
58         "TOFROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::Tofrom)),
59     maybe(":" >> construct<OmpDefaultmapClause::VariableCategory>("SCALAR" >>
60                      pure(OmpDefaultmapClause::VariableCategory::Scalar)))))
61 
62 // 2.7.1 SCHEDULE ([modifier1 [, modifier2]:]kind[, chunk_size])
63 //       Modifier ->  MONITONIC | NONMONOTONIC | SIMD
64 //       kind -> STATIC | DYNAMIC | GUIDED | AUTO | RUNTIME
65 //       chunk_size -> ScalarIntExpr
66 TYPE_PARSER(construct<OmpScheduleModifierType>(
67     "MONOTONIC" >> pure(OmpScheduleModifierType::ModType::Monotonic) ||
68     "NONMONOTONIC" >> pure(OmpScheduleModifierType::ModType::Nonmonotonic) ||
69     "SIMD" >> pure(OmpScheduleModifierType::ModType::Simd)))
70 
71 TYPE_PARSER(construct<OmpScheduleModifier>(Parser<OmpScheduleModifierType>{},
72     maybe("," >> Parser<OmpScheduleModifierType>{}) / ":"))
73 
74 TYPE_PARSER(construct<OmpScheduleClause>(maybe(Parser<OmpScheduleModifier>{}),
75     "STATIC" >> pure(OmpScheduleClause::ScheduleType::Static) ||
76         "DYNAMIC" >> pure(OmpScheduleClause::ScheduleType::Dynamic) ||
77         "GUIDED" >> pure(OmpScheduleClause::ScheduleType::Guided) ||
78         "AUTO" >> pure(OmpScheduleClause::ScheduleType::Auto) ||
79         "RUNTIME" >> pure(OmpScheduleClause::ScheduleType::Runtime),
80     maybe("," >> scalarIntExpr)))
81 
82 // 2.12 IF (directive-name-modifier: scalar-logical-expr)
83 TYPE_PARSER(construct<OmpIfClause>(
84     maybe(
85         ("PARALLEL" >> pure(OmpIfClause::DirectiveNameModifier::Parallel) ||
86             "TARGET ENTER DATA" >>
87                 pure(OmpIfClause::DirectiveNameModifier::TargetEnterData) ||
88             "TARGET EXIT DATA" >>
89                 pure(OmpIfClause::DirectiveNameModifier::TargetExitData) ||
90             "TARGET DATA" >>
91                 pure(OmpIfClause::DirectiveNameModifier::TargetData) ||
92             "TARGET UPDATE" >>
93                 pure(OmpIfClause::DirectiveNameModifier::TargetUpdate) ||
94             "TARGET" >> pure(OmpIfClause::DirectiveNameModifier::Target) ||
95             "TASK"_id >> pure(OmpIfClause::DirectiveNameModifier::Task) ||
96             "TASKLOOP" >> pure(OmpIfClause::DirectiveNameModifier::Taskloop)) /
97         ":"),
98     scalarLogicalExpr))
99 
100 // 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
101 TYPE_PARSER(construct<OmpReductionOperator>(Parser<DefinedOperator>{}) ||
102     construct<OmpReductionOperator>(Parser<ProcedureDesignator>{}))
103 
104 TYPE_PARSER(construct<OmpReductionClause>(
105     Parser<OmpReductionOperator>{} / ":", Parser<OmpObjectList>{}))
106 
107 // OMP 5.0 2.11.4  ALLOCATE ([allocator:] variable-name-list)
108 TYPE_PARSER(construct<OmpAllocateClause>(
109     maybe(construct<OmpAllocateClause::Allocator>(scalarIntExpr) / ":"),
110     Parser<OmpObjectList>{}))
111 
112 // 2.13.9 DEPEND (SOURCE | SINK : vec | (IN | OUT | INOUT) : list
113 TYPE_PARSER(construct<OmpDependSinkVecLength>(
114     Parser<DefinedOperator>{}, scalarIntConstantExpr))
115 
116 TYPE_PARSER(
117     construct<OmpDependSinkVec>(name, maybe(Parser<OmpDependSinkVecLength>{})))
118 
119 TYPE_PARSER(
120     construct<OmpDependenceType>("IN"_id >> pure(OmpDependenceType::Type::In) ||
121         "INOUT" >> pure(OmpDependenceType::Type::Inout) ||
122         "OUT" >> pure(OmpDependenceType::Type::Out)))
123 
124 TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
125     construct<OmpDependClause>(construct<OmpDependClause::Sink>(
126         "SINK :" >> nonemptyList(Parser<OmpDependSinkVec>{}))) ||
127         construct<OmpDependClause>(
128             construct<OmpDependClause::Source>("SOURCE"_tok)) ||
129         construct<OmpDependClause>(construct<OmpDependClause::InOut>(
130             Parser<OmpDependenceType>{}, ":" >> nonemptyList(designator))))
131 
132 // 2.15.3.7 LINEAR (linear-list: linear-step)
133 //          linear-list -> list | modifier(list)
134 //          linear-modifier -> REF | VAL | UVAL
135 TYPE_PARSER(
136     construct<OmpLinearModifier>("REF" >> pure(OmpLinearModifier::Type::Ref) ||
137         "VAL" >> pure(OmpLinearModifier::Type::Val) ||
138         "UVAL" >> pure(OmpLinearModifier::Type::Uval)))
139 
140 TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US,
141     construct<OmpLinearClause>(
142         construct<OmpLinearClause>(construct<OmpLinearClause::WithModifier>(
143             Parser<OmpLinearModifier>{}, parenthesized(nonemptyList(name)),
144             maybe(":" >> scalarIntConstantExpr))) ||
145         construct<OmpLinearClause>(construct<OmpLinearClause::WithoutModifier>(
146             nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))))
147 
148 // 2.8.1 ALIGNED (list: alignment)
149 TYPE_PARSER(construct<OmpAlignedClause>(
150     nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))
151 
152 TYPE_PARSER(
153     construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/"))
154 
155 TYPE_PARSER(
156     "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
157     "ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
158     "ALIGNED" >> construct<OmpClause>(construct<OmpClause::Aligned>(
159                      parenthesized(Parser<OmpAlignedClause>{}))) ||
160     "ALLOCATE" >> construct<OmpClause>(construct<OmpClause::Allocate>(
161                       parenthesized(Parser<OmpAllocateClause>{}))) ||
162     "ALLOCATOR" >> construct<OmpClause>(construct<OmpClause::Allocator>(
163                        parenthesized(scalarIntExpr))) ||
164     "COLLAPSE" >> construct<OmpClause>(construct<OmpClause::Collapse>(
165                       parenthesized(scalarIntConstantExpr))) ||
166     "COPYIN" >> construct<OmpClause>(construct<OmpClause::Copyin>(
167                     parenthesized(Parser<OmpObjectList>{}))) ||
168     "COPYPRIVATE" >> construct<OmpClause>(construct<OmpClause::Copyprivate>(
169                          (parenthesized(Parser<OmpObjectList>{})))) ||
170     "DEFAULT"_id >> construct<OmpClause>(construct<OmpClause::Default>(
171                         parenthesized(Parser<OmpDefaultClause>{}))) ||
172     "DEFAULTMAP" >> construct<OmpClause>(construct<OmpClause::Defaultmap>(
173                         parenthesized(Parser<OmpDefaultmapClause>{}))) ||
174     "DEPEND" >> construct<OmpClause>(construct<OmpClause::Depend>(
175                     parenthesized(Parser<OmpDependClause>{}))) ||
176     "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
177                     parenthesized(scalarIntExpr))) ||
178     "DIST_SCHEDULE" >>
179         construct<OmpClause>(construct<OmpClause::DistSchedule>(
180             parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||
181     "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
182                    parenthesized(scalarLogicalExpr))) ||
183     "FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
184                           parenthesized(Parser<OmpObjectList>{}))) ||
185     "FROM" >> construct<OmpClause>(construct<OmpClause::From>(
186                   parenthesized(Parser<OmpObjectList>{}))) ||
187     "GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
188                        parenthesized(scalarIntExpr))) ||
189     "HINT" >> construct<OmpClause>(
190                   construct<OmpClause::Hint>(parenthesized(constantExpr))) ||
191     "IF" >> construct<OmpClause>(construct<OmpClause::If>(
192                 parenthesized(Parser<OmpIfClause>{}))) ||
193     "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
194     "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
195                            parenthesized(nonemptyList(name)))) ||
196     "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
197                          parenthesized(Parser<OmpObjectList>{}))) ||
198     "LINEAR" >> construct<OmpClause>(construct<OmpClause::Linear>(
199                     parenthesized(Parser<OmpLinearClause>{}))) ||
200     "LINK" >> construct<OmpClause>(construct<OmpClause::Link>(
201                   parenthesized(Parser<OmpObjectList>{}))) ||
202     "MAP" >> construct<OmpClause>(construct<OmpClause::Map>(
203                  parenthesized(Parser<OmpMapClause>{}))) ||
204     "MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) ||
205     "NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) ||
206     "NONTEMPORAL" >> construct<OmpClause>(construct<OmpClause::Nontemporal>(
207                          parenthesized(nonemptyList(name)))) ||
208     "NOTINBRANCH" >>
209         construct<OmpClause>(construct<OmpClause::Notinbranch>()) ||
210     "NOWAIT" >> construct<OmpClause>(construct<OmpClause::Nowait>()) ||
211     "NUM_TASKS" >> construct<OmpClause>(construct<OmpClause::NumTasks>(
212                        parenthesized(scalarIntExpr))) ||
213     "NUM_TEAMS" >> construct<OmpClause>(construct<OmpClause::NumTeams>(
214                        parenthesized(scalarIntExpr))) ||
215     "NUM_THREADS" >> construct<OmpClause>(construct<OmpClause::NumThreads>(
216                          parenthesized(scalarIntExpr))) ||
217     "ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>(
218                      maybe(parenthesized(scalarIntConstantExpr)))) ||
219     "PRIORITY" >> construct<OmpClause>(construct<OmpClause::Priority>(
220                       parenthesized(scalarIntExpr))) ||
221     "PRIVATE" >> construct<OmpClause>(construct<OmpClause::Private>(
222                      parenthesized(Parser<OmpObjectList>{}))) ||
223     "PROC_BIND" >> construct<OmpClause>(construct<OmpClause::ProcBind>(
224                        parenthesized(Parser<OmpProcBindClause>{}))) ||
225     "REDUCTION" >> construct<OmpClause>(construct<OmpClause::Reduction>(
226                        parenthesized(Parser<OmpReductionClause>{}))) ||
227     "TASK_REDUCTION" >>
228         construct<OmpClause>(construct<OmpClause::TaskReduction>(
229             parenthesized(Parser<OmpReductionClause>{}))) ||
230     "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()) ||
231     "RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
232     "SAFELEN" >> construct<OmpClause>(construct<OmpClause::Safelen>(
233                      parenthesized(scalarIntConstantExpr))) ||
234     "SCHEDULE" >> construct<OmpClause>(construct<OmpClause::Schedule>(
235                       parenthesized(Parser<OmpScheduleClause>{}))) ||
236     "SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) ||
237     "SHARED" >> construct<OmpClause>(construct<OmpClause::Shared>(
238                     parenthesized(Parser<OmpObjectList>{}))) ||
239     "SIMD"_id >> construct<OmpClause>(construct<OmpClause::Simd>()) ||
240     "SIMDLEN" >> construct<OmpClause>(construct<OmpClause::Simdlen>(
241                      parenthesized(scalarIntConstantExpr))) ||
242     "THREADS" >> construct<OmpClause>(construct<OmpClause::Threads>()) ||
243     "THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
244                           parenthesized(scalarIntExpr))) ||
245     "TO" >> construct<OmpClause>(construct<OmpClause::To>(
246                 parenthesized(Parser<OmpObjectList>{}))) ||
247     "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
248                             parenthesized(nonemptyList(name)))) ||
249     "UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>(
250                      parenthesized(nonemptyList(name)))) ||
251     "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()))
252 
253 // [Clause, [Clause], ...]
254 TYPE_PARSER(sourced(construct<OmpClauseList>(
255     many(maybe(","_tok) >> sourced(Parser<OmpClause>{})))))
256 
257 // 2.1 (variable | /common-block | array-sections)
258 TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{})))
259 
260 // Omp directives enclosing do loop
261 TYPE_PARSER(sourced(construct<OmpLoopDirective>(first(
262     "DISTRIBUTE PARALLEL DO SIMD" >>
263         pure(llvm::omp::Directive::OMPD_distribute_parallel_do_simd),
264     "DISTRIBUTE PARALLEL DO" >>
265         pure(llvm::omp::Directive::OMPD_distribute_parallel_do),
266     "DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_distribute_simd),
267     "DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_distribute),
268     "DO SIMD" >> pure(llvm::omp::Directive::OMPD_do_simd),
269     "DO" >> pure(llvm::omp::Directive::OMPD_do),
270     "PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_do_simd),
271     "PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_parallel_do),
272     "SIMD" >> pure(llvm::omp::Directive::OMPD_simd),
273     "TARGET PARALLEL DO SIMD" >>
274         pure(llvm::omp::Directive::OMPD_target_parallel_do_simd),
275     "TARGET PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_target_parallel_do),
276     "TARGET SIMD" >> pure(llvm::omp::Directive::OMPD_target_simd),
277     "TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
278         pure(llvm::omp::Directive::
279                 OMPD_target_teams_distribute_parallel_do_simd),
280     "TARGET TEAMS DISTRIBUTE PARALLEL DO" >>
281         pure(llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do),
282     "TARGET TEAMS DISTRIBUTE SIMD" >>
283         pure(llvm::omp::Directive::OMPD_target_teams_distribute_simd),
284     "TARGET TEAMS DISTRIBUTE" >>
285         pure(llvm::omp::Directive::OMPD_target_teams_distribute),
286     "TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_taskloop_simd),
287     "TASKLOOP" >> pure(llvm::omp::Directive::OMPD_taskloop),
288     "TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
289         pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd),
290     "TEAMS DISTRIBUTE PARALLEL DO" >>
291         pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do),
292     "TEAMS DISTRIBUTE SIMD" >>
293         pure(llvm::omp::Directive::OMPD_teams_distribute_simd),
294     "TEAMS DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_teams_distribute)))))
295 
296 TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>(
297     sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{})))
298 
299 // 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP
300 TYPE_PARSER(sourced(construct<OmpCancelType>(
301     first("PARALLEL" >> pure(OmpCancelType::Type::Parallel),
302         "SECTIONS" >> pure(OmpCancelType::Type::Sections),
303         "DO" >> pure(OmpCancelType::Type::Do),
304         "TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup)))))
305 
306 // 2.14.2 Cancellation Point construct
307 TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>(
308     verbatim("CANCELLATION POINT"_tok), Parser<OmpCancelType>{})))
309 
310 // 2.14.1 Cancel construct
311 TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(verbatim("CANCEL"_tok),
312     Parser<OmpCancelType>{}, maybe("IF" >> parenthesized(scalarLogicalExpr)))))
313 
314 // 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
315 //        memory-order-clause ->
316 //                               seq_cst
317 //                               acq_rel
318 //                               release
319 //                               acquire
320 //                               relaxed
321 TYPE_PARSER(sourced(construct<OmpMemoryOrderClause>(
322     sourced("SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) ||
323         "ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
324         "RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
325         "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
326         "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>())))))
327 
328 // 2.17.7 Atomic construct
329 //        atomic-clause -> memory-order-clause | HINT(hint-expression)
330 TYPE_PARSER(sourced(construct<OmpAtomicClause>(
331     construct<OmpAtomicClause>(Parser<OmpMemoryOrderClause>{}) ||
332     construct<OmpAtomicClause>("HINT" >>
333         sourced(construct<OmpClause>(
334             construct<OmpClause::Hint>(parenthesized(constantExpr))))))))
335 
336 // atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
337 TYPE_PARSER(sourced(construct<OmpAtomicClauseList>(
338     many(maybe(","_tok) >> sourced(Parser<OmpAtomicClause>{})))))
339 
340 TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok),
341     many(maybe(","_tok) >> sourced(Parser<OmpMemoryOrderClause>{})),
342     maybe(parenthesized(Parser<OmpObjectList>{})))))
343 
344 // Simple Standalone Directives
345 TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
346     "BARRIER" >> pure(llvm::omp::Directive::OMPD_barrier),
347     "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
348     "TARGET ENTER DATA" >> pure(llvm::omp::Directive::OMPD_target_enter_data),
349     "TARGET EXIT DATA" >> pure(llvm::omp::Directive::OMPD_target_exit_data),
350     "TARGET UPDATE" >> pure(llvm::omp::Directive::OMPD_target_update),
351     "TASKWAIT" >> pure(llvm::omp::Directive::OMPD_taskwait),
352     "TASKYIELD" >> pure(llvm::omp::Directive::OMPD_taskyield)))))
353 
354 TYPE_PARSER(sourced(construct<OpenMPSimpleStandaloneConstruct>(
355     Parser<OmpSimpleStandaloneDirective>{}, Parser<OmpClauseList>{})))
356 
357 // Standalone Constructs
358 TYPE_PARSER(
359     sourced(construct<OpenMPStandaloneConstruct>(
360                 Parser<OpenMPSimpleStandaloneConstruct>{}) ||
361         construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
362         construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
363         construct<OpenMPStandaloneConstruct>(
364             Parser<OpenMPCancellationPointConstruct>{})) /
365     endOfLine)
366 
367 // Directives enclosing structured-block
368 TYPE_PARSER(construct<OmpBlockDirective>(first(
369     "MASTER" >> pure(llvm::omp::Directive::OMPD_master),
370     "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
371     "PARALLEL WORKSHARE" >> pure(llvm::omp::Directive::OMPD_parallel_workshare),
372     "PARALLEL" >> pure(llvm::omp::Directive::OMPD_parallel),
373     "SINGLE" >> pure(llvm::omp::Directive::OMPD_single),
374     "TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data),
375     "TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel),
376     "TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams),
377     "TARGET" >> pure(llvm::omp::Directive::OMPD_target),
378     "TASK"_id >> pure(llvm::omp::Directive::OMPD_task),
379     "TASKGROUP" >> pure(llvm::omp::Directive::OMPD_taskgroup),
380     "TEAMS" >> pure(llvm::omp::Directive::OMPD_teams),
381     "WORKSHARE" >> pure(llvm::omp::Directive::OMPD_workshare))))
382 
383 TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>(
384     sourced(Parser<OmpBlockDirective>{}), Parser<OmpClauseList>{})))
385 
386 TYPE_PARSER(construct<OmpReductionInitializerClause>(
387     "INITIALIZER" >> parenthesized("OMP_PRIV =" >> expr)))
388 
389 // 2.16 Declare Reduction Construct
390 TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
391     verbatim("DECLARE REDUCTION"_tok),
392     "(" >> Parser<OmpReductionOperator>{} / ":",
393     nonemptyList(Parser<DeclarationTypeSpec>{}) / ":",
394     Parser<OmpReductionCombiner>{} / ")",
395     maybe(Parser<OmpReductionInitializerClause>{}))))
396 
397 // declare-target with list
398 TYPE_PARSER(sourced(construct<OmpDeclareTargetWithList>(
399     parenthesized(Parser<OmpObjectList>{}))))
400 
401 // declare-target with clause
402 TYPE_PARSER(
403     sourced(construct<OmpDeclareTargetWithClause>(Parser<OmpClauseList>{})))
404 
405 // declare-target-specifier
406 TYPE_PARSER(
407     construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithList>{}) ||
408     construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithClause>{}))
409 
410 // 2.10.6 Declare Target Construct
411 TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
412     verbatim("DECLARE TARGET"_tok), Parser<OmpDeclareTargetSpecifier>{})))
413 
414 TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) ||
415     construct<OmpReductionCombiner>(
416         construct<OmpReductionCombiner::FunctionCombiner>(
417             construct<Call>(Parser<ProcedureDesignator>{},
418                 parenthesized(optionalList(actualArgSpec))))))
419 
420 // 2.17.7 atomic -> ATOMIC [clause [,]] atomic-clause [[,] clause] |
421 //                  ATOMIC [clause]
422 //       clause -> memory-order-clause | HINT(hint-expression)
423 //       memory-order-clause -> SEQ_CST | ACQ_REL | RELEASE | ACQUIRE | RELAXED
424 //       atomic-clause -> READ | WRITE | UPDATE | CAPTURE
425 
426 // OMP END ATOMIC
427 TYPE_PARSER(construct<OmpEndAtomic>(startOmpLine >> "END ATOMIC"_tok))
428 
429 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] READ [MEMORY-ORDER-CLAUSE-LIST]
430 TYPE_PARSER("ATOMIC" >>
431     construct<OmpAtomicRead>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
432         verbatim("READ"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
433         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
434 
435 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] CAPTURE [MEMORY-ORDER-CLAUSE-LIST]
436 TYPE_PARSER("ATOMIC" >>
437     construct<OmpAtomicCapture>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
438         verbatim("CAPTURE"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
439         statement(assignmentStmt), statement(assignmentStmt),
440         Parser<OmpEndAtomic>{} / endOmpLine))
441 
442 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST]
443 TYPE_PARSER("ATOMIC" >>
444     construct<OmpAtomicUpdate>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
445         verbatim("UPDATE"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
446         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
447 
448 // OMP ATOMIC [atomic-clause-list]
449 TYPE_PARSER(construct<OmpAtomic>(verbatim("ATOMIC"_tok),
450     Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
451     maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
452 
453 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] WRITE [MEMORY-ORDER-CLAUSE-LIST]
454 TYPE_PARSER("ATOMIC" >>
455     construct<OmpAtomicWrite>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
456         verbatim("WRITE"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
457         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
458 
459 // Atomic Construct
460 TYPE_PARSER(construct<OpenMPAtomicConstruct>(Parser<OmpAtomicRead>{}) ||
461     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCapture>{}) ||
462     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicWrite>{}) ||
463     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicUpdate>{}) ||
464     construct<OpenMPAtomicConstruct>(Parser<OmpAtomic>{}))
465 
466 // 2.13.2 OMP CRITICAL
467 TYPE_PARSER(startOmpLine >>
468     sourced(construct<OmpEndCriticalDirective>(
469         verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) /
470         endOmpLine)
471 TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok),
472                 maybe(parenthesized(name)), maybe(Parser<OmpClause>{}))) /
473     endOmpLine)
474 
475 TYPE_PARSER(construct<OpenMPCriticalConstruct>(
476     Parser<OmpCriticalDirective>{}, block, Parser<OmpEndCriticalDirective>{}))
477 
478 // 2.11.3 Executable Allocate directive
479 TYPE_PARSER(
480     sourced(construct<OpenMPExecutableAllocate>(verbatim("ALLOCATE"_tok),
481         maybe(parenthesized(Parser<OmpObjectList>{})), Parser<OmpClauseList>{},
482         maybe(nonemptyList(Parser<OpenMPDeclarativeAllocate>{})) / endOmpLine,
483         statement(allocateStmt))))
484 
485 // 2.8.2 Declare Simd construct
486 TYPE_PARSER(
487     sourced(construct<OpenMPDeclareSimdConstruct>(verbatim("DECLARE SIMD"_tok),
488         maybe(parenthesized(name)), Parser<OmpClauseList>{})))
489 
490 // 2.15.2 Threadprivate directive
491 TYPE_PARSER(sourced(construct<OpenMPThreadprivate>(
492     verbatim("THREADPRIVATE"_tok), parenthesized(Parser<OmpObjectList>{}))))
493 
494 // 2.11.3 Declarative Allocate directive
495 TYPE_PARSER(
496     sourced(construct<OpenMPDeclarativeAllocate>(verbatim("ALLOCATE"_tok),
497         parenthesized(Parser<OmpObjectList>{}), Parser<OmpClauseList>{})) /
498     lookAhead(endOmpLine / !statement(allocateStmt)))
499 
500 // Declarative constructs
501 TYPE_PARSER(startOmpLine >>
502     sourced(construct<OpenMPDeclarativeConstruct>(
503                 Parser<OpenMPDeclareReductionConstruct>{}) ||
504         construct<OpenMPDeclarativeConstruct>(
505             Parser<OpenMPDeclareSimdConstruct>{}) ||
506         construct<OpenMPDeclarativeConstruct>(
507             Parser<OpenMPDeclareTargetConstruct>{}) ||
508         construct<OpenMPDeclarativeConstruct>(
509             Parser<OpenMPDeclarativeAllocate>{}) ||
510         construct<OpenMPDeclarativeConstruct>(Parser<OpenMPThreadprivate>{})) /
511         endOmpLine)
512 
513 // Block Construct
514 TYPE_PARSER(construct<OpenMPBlockConstruct>(
515     Parser<OmpBeginBlockDirective>{} / endOmpLine, block,
516     Parser<OmpEndBlockDirective>{} / endOmpLine))
517 
518 // OMP SECTIONS Directive
519 TYPE_PARSER(construct<OmpSectionsDirective>(first(
520     "SECTIONS" >> pure(llvm::omp::Directive::OMPD_sections),
521     "PARALLEL SECTIONS" >> pure(llvm::omp::Directive::OMPD_parallel_sections))))
522 
523 // OMP BEGIN and END SECTIONS Directive
524 TYPE_PARSER(sourced(construct<OmpBeginSectionsDirective>(
525     sourced(Parser<OmpSectionsDirective>{}), Parser<OmpClauseList>{})))
526 TYPE_PARSER(
527     startOmpLine >> sourced(construct<OmpEndSectionsDirective>(
528                         sourced("END"_tok >> Parser<OmpSectionsDirective>{}),
529                         Parser<OmpClauseList>{})))
530 
531 // OMP SECTION-BLOCK
532 TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >>
533     construct<OmpSectionBlocks>(
534         nonemptySeparated(block, startOmpLine >> "SECTION"_tok / endOmpLine)))
535 
536 // OMP SECTIONS (2.7.2), PARALLEL SECTIONS (2.11.2)
537 TYPE_PARSER(construct<OpenMPSectionsConstruct>(
538     Parser<OmpBeginSectionsDirective>{} / endOmpLine,
539     Parser<OmpSectionBlocks>{}, Parser<OmpEndSectionsDirective>{} / endOmpLine))
540 
541 TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
542     startOmpLine >>
543         first(construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}),
544             construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}),
545             construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}),
546             // OpenMPBlockConstruct is attempted before
547             // OpenMPStandaloneConstruct to resolve !$OMP ORDERED
548             construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}),
549             construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}),
550             construct<OpenMPConstruct>(Parser<OpenMPExecutableAllocate>{}),
551             construct<OpenMPConstruct>(Parser<OpenMPDeclarativeAllocate>{}),
552             construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{})))
553 
554 // END OMP Block directives
555 TYPE_PARSER(
556     startOmpLine >> sourced(construct<OmpEndBlockDirective>(
557                         sourced("END"_tok >> Parser<OmpBlockDirective>{}),
558                         Parser<OmpClauseList>{})))
559 
560 // END OMP Loop directives
561 TYPE_PARSER(
562     startOmpLine >> sourced(construct<OmpEndLoopDirective>(
563                         sourced("END"_tok >> Parser<OmpLoopDirective>{}),
564                         Parser<OmpClauseList>{})))
565 
566 TYPE_PARSER(construct<OpenMPLoopConstruct>(
567     Parser<OmpBeginLoopDirective>{} / endOmpLine))
568 } // namespace Fortran::parser
569