xref: /llvm-project/flang/lib/Parser/openmp-parsers.cpp (revision 65049d16100af360674659fb56e8f9bec96a0836)
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>{} / ":", nonemptyList(designator)))
106 
107 // 2.13.9 DEPEND (SOURCE | SINK : vec | (IN | OUT | INOUT) : list
108 TYPE_PARSER(construct<OmpDependSinkVecLength>(
109     Parser<DefinedOperator>{}, scalarIntConstantExpr))
110 
111 TYPE_PARSER(
112     construct<OmpDependSinkVec>(name, maybe(Parser<OmpDependSinkVecLength>{})))
113 
114 TYPE_PARSER(
115     construct<OmpDependenceType>("IN"_id >> pure(OmpDependenceType::Type::In) ||
116         "INOUT" >> pure(OmpDependenceType::Type::Inout) ||
117         "OUT" >> pure(OmpDependenceType::Type::Out)))
118 
119 TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
120     construct<OmpDependClause>(construct<OmpDependClause::Sink>(
121         "SINK :" >> nonemptyList(Parser<OmpDependSinkVec>{}))) ||
122         construct<OmpDependClause>(
123             construct<OmpDependClause::Source>("SOURCE"_tok)) ||
124         construct<OmpDependClause>(construct<OmpDependClause::InOut>(
125             Parser<OmpDependenceType>{}, ":" >> nonemptyList(designator))))
126 
127 // 2.15.3.7 LINEAR (linear-list: linear-step)
128 //          linear-list -> list | modifier(list)
129 //          linear-modifier -> REF | VAL | UVAL
130 TYPE_PARSER(
131     construct<OmpLinearModifier>("REF" >> pure(OmpLinearModifier::Type::Ref) ||
132         "VAL" >> pure(OmpLinearModifier::Type::Val) ||
133         "UVAL" >> pure(OmpLinearModifier::Type::Uval)))
134 
135 TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US,
136     construct<OmpLinearClause>(
137         construct<OmpLinearClause>(construct<OmpLinearClause::WithModifier>(
138             Parser<OmpLinearModifier>{}, parenthesized(nonemptyList(name)),
139             maybe(":" >> scalarIntConstantExpr))) ||
140         construct<OmpLinearClause>(construct<OmpLinearClause::WithoutModifier>(
141             nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))))
142 
143 // 2.8.1 ALIGNED (list: alignment)
144 TYPE_PARSER(construct<OmpAlignedClause>(
145     nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))
146 
147 TYPE_PARSER(
148     construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/"))
149 
150 TYPE_PARSER("ALIGNED" >>
151         construct<OmpClause>(parenthesized(Parser<OmpAlignedClause>{})) ||
152     "COLLAPSE" >> construct<OmpClause>(construct<OmpClause::Collapse>(
153                       parenthesized(scalarIntConstantExpr))) ||
154     "COPYIN" >> construct<OmpClause>(construct<OmpClause::Copyin>(
155                     parenthesized(Parser<OmpObjectList>{}))) ||
156     "COPYPRIVATE" >> construct<OmpClause>(construct<OmpClause::Copyprivate>(
157                          (parenthesized(Parser<OmpObjectList>{})))) ||
158     "DEFAULT"_id >>
159         construct<OmpClause>(parenthesized(Parser<OmpDefaultClause>{})) ||
160     "DEFAULTMAP" >>
161         construct<OmpClause>(parenthesized(Parser<OmpDefaultmapClause>{})) ||
162     "DEPEND" >>
163         construct<OmpClause>(parenthesized(Parser<OmpDependClause>{})) ||
164     "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
165                     parenthesized(scalarIntExpr))) ||
166     "DIST_SCHEDULE" >>
167         construct<OmpClause>(construct<OmpClause::DistSchedule>(
168             parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||
169     "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
170                    parenthesized(scalarLogicalExpr))) ||
171     "FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
172                           parenthesized(Parser<OmpObjectList>{}))) ||
173     "FROM" >> construct<OmpClause>(construct<OmpClause::From>(
174                   parenthesized(Parser<OmpObjectList>{}))) ||
175     "GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
176                        parenthesized(scalarIntExpr))) ||
177     "IF" >> construct<OmpClause>(parenthesized(Parser<OmpIfClause>{})) ||
178     "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
179     "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
180                            parenthesized(nonemptyList(name)))) ||
181     "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
182                          parenthesized(Parser<OmpObjectList>{}))) ||
183     "LINEAR" >>
184         construct<OmpClause>(parenthesized(Parser<OmpLinearClause>{})) ||
185     "LINK" >> construct<OmpClause>(construct<OmpClause::Link>(
186                   parenthesized(Parser<OmpObjectList>{}))) ||
187     "MAP" >> construct<OmpClause>(parenthesized(Parser<OmpMapClause>{})) ||
188     "MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) ||
189     "NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) ||
190     "NOTINBRANCH" >>
191         construct<OmpClause>(construct<OmpClause::Notinbranch>()) ||
192     "NOWAIT" >> construct<OmpClause>(construct<OmpNowait>()) ||
193     "NUM_TASKS" >> construct<OmpClause>(construct<OmpClause::NumTasks>(
194                        parenthesized(scalarIntExpr))) ||
195     "NUM_TEAMS" >> construct<OmpClause>(construct<OmpClause::NumTeams>(
196                        parenthesized(scalarIntExpr))) ||
197     "NUM_THREADS" >> construct<OmpClause>(construct<OmpClause::NumThreads>(
198                          parenthesized(scalarIntExpr))) ||
199     "ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>(
200                      maybe(parenthesized(scalarIntConstantExpr)))) ||
201     "PRIORITY" >> construct<OmpClause>(construct<OmpClause::Priority>(
202                       parenthesized(scalarIntExpr))) ||
203     "PRIVATE" >> construct<OmpClause>(construct<OmpClause::Private>(
204                      parenthesized(Parser<OmpObjectList>{}))) ||
205     "PROC_BIND" >>
206         construct<OmpClause>(parenthesized(Parser<OmpProcBindClause>{})) ||
207     "REDUCTION" >>
208         construct<OmpClause>(parenthesized(Parser<OmpReductionClause>{})) ||
209     "SAFELEN" >> construct<OmpClause>(construct<OmpClause::Safelen>(
210                      parenthesized(scalarIntConstantExpr))) ||
211     "SCHEDULE" >>
212         construct<OmpClause>(parenthesized(Parser<OmpScheduleClause>{})) ||
213     "SHARED" >> construct<OmpClause>(construct<OmpClause::Shared>(
214                     parenthesized(Parser<OmpObjectList>{}))) ||
215     "SIMD"_id >> construct<OmpClause>(construct<OmpClause::Simd>()) ||
216     "SIMDLEN" >> construct<OmpClause>(construct<OmpClause::Simdlen>(
217                      parenthesized(scalarIntConstantExpr))) ||
218     "THREADS" >> construct<OmpClause>(construct<OmpClause::Threads>()) ||
219     "THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
220                           parenthesized(scalarIntExpr))) ||
221     "TO" >> construct<OmpClause>(construct<OmpClause::To>(
222                 parenthesized(Parser<OmpObjectList>{}))) ||
223     "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
224                             parenthesized(nonemptyList(name)))) ||
225     "UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>(
226                      parenthesized(nonemptyList(name)))) ||
227     "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()))
228 
229 // [Clause, [Clause], ...]
230 TYPE_PARSER(sourced(construct<OmpClauseList>(
231     many(maybe(","_tok) >> sourced(Parser<OmpClause>{})))))
232 
233 // 2.1 (variable | /common-block | array-sections)
234 TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{})))
235 
236 // Omp directives enclosing do loop
237 TYPE_PARSER(sourced(construct<OmpLoopDirective>(first(
238     "DISTRIBUTE PARALLEL DO SIMD" >>
239         pure(llvm::omp::Directive::OMPD_distribute_parallel_do_simd),
240     "DISTRIBUTE PARALLEL DO" >>
241         pure(llvm::omp::Directive::OMPD_distribute_parallel_do),
242     "DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_distribute_simd),
243     "DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_distribute),
244     "DO SIMD" >> pure(llvm::omp::Directive::OMPD_do_simd),
245     "DO" >> pure(llvm::omp::Directive::OMPD_do),
246     "PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_do_simd),
247     "PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_parallel_do),
248     "SIMD" >> pure(llvm::omp::Directive::OMPD_simd),
249     "TARGET PARALLEL DO SIMD" >>
250         pure(llvm::omp::Directive::OMPD_target_parallel_do_simd),
251     "TARGET PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_target_parallel_do),
252     "TARGET SIMD" >> pure(llvm::omp::Directive::OMPD_target_simd),
253     "TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
254         pure(llvm::omp::Directive::
255                 OMPD_target_teams_distribute_parallel_do_simd),
256     "TARGET TEAMS DISTRIBUTE PARALLEL DO" >>
257         pure(llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do),
258     "TARGET TEAMS DISTRIBUTE SIMD" >>
259         pure(llvm::omp::Directive::OMPD_target_teams_distribute_simd),
260     "TARGET TEAMS DISTRIBUTE" >>
261         pure(llvm::omp::Directive::OMPD_target_teams_distribute),
262     "TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_taskloop_simd),
263     "TASKLOOP" >> pure(llvm::omp::Directive::OMPD_taskloop),
264     "TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
265         pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd),
266     "TEAMS DISTRIBUTE PARALLEL DO" >>
267         pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do),
268     "TEAMS DISTRIBUTE SIMD" >>
269         pure(llvm::omp::Directive::OMPD_teams_distribute_simd),
270     "TEAMS DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_teams_distribute)))))
271 
272 TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>(
273     sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{})))
274 
275 // 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP
276 TYPE_PARSER(sourced(construct<OmpCancelType>(
277     first("PARALLEL" >> pure(OmpCancelType::Type::Parallel),
278         "SECTIONS" >> pure(OmpCancelType::Type::Sections),
279         "DO" >> pure(OmpCancelType::Type::Do),
280         "TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup)))))
281 
282 // 2.14.2 Cancellation Point construct
283 TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>(
284     verbatim("CANCELLATION POINT"_tok), Parser<OmpCancelType>{})))
285 
286 // 2.14.1 Cancel construct
287 TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(verbatim("CANCEL"_tok),
288     Parser<OmpCancelType>{}, maybe("IF" >> parenthesized(scalarLogicalExpr)))))
289 
290 // 2.17.8 Flush construct [OpenMP 5.0]
291 //        flush -> FLUSH [memory-order-clause] [(variable-name-list)]
292 //        memory-order-clause -> acq_rel
293 //                               release
294 //                               acquire
295 TYPE_PARSER(sourced(construct<OmpFlushMemoryClause>(
296     "ACQ_REL" >> pure(OmpFlushMemoryClause::FlushMemoryOrder::AcqRel) ||
297     "RELEASE" >> pure(OmpFlushMemoryClause::FlushMemoryOrder::Release) ||
298     "ACQUIRE" >> pure(OmpFlushMemoryClause::FlushMemoryOrder::Acquire))))
299 
300 TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok),
301     maybe(Parser<OmpFlushMemoryClause>{}),
302     maybe(parenthesized(Parser<OmpObjectList>{})))))
303 
304 // Simple Standalone Directives
305 TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
306     "BARRIER" >> pure(llvm::omp::Directive::OMPD_barrier),
307     "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
308     "TARGET ENTER DATA" >> pure(llvm::omp::Directive::OMPD_target_enter_data),
309     "TARGET EXIT DATA" >> pure(llvm::omp::Directive::OMPD_target_exit_data),
310     "TARGET UPDATE" >> pure(llvm::omp::Directive::OMPD_target_update),
311     "TASKWAIT" >> pure(llvm::omp::Directive::OMPD_taskwait),
312     "TASKYIELD" >> pure(llvm::omp::Directive::OMPD_taskyield)))))
313 
314 TYPE_PARSER(sourced(construct<OpenMPSimpleStandaloneConstruct>(
315     Parser<OmpSimpleStandaloneDirective>{}, Parser<OmpClauseList>{})))
316 
317 // Standalone Constructs
318 TYPE_PARSER(
319     sourced(construct<OpenMPStandaloneConstruct>(
320                 Parser<OpenMPSimpleStandaloneConstruct>{}) ||
321         construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
322         construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
323         construct<OpenMPStandaloneConstruct>(
324             Parser<OpenMPCancellationPointConstruct>{})) /
325     endOfLine)
326 
327 // Directives enclosing structured-block
328 TYPE_PARSER(construct<OmpBlockDirective>(first(
329     "MASTER" >> pure(llvm::omp::Directive::OMPD_master),
330     "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
331     "PARALLEL WORKSHARE" >> pure(llvm::omp::Directive::OMPD_parallel_workshare),
332     "PARALLEL" >> pure(llvm::omp::Directive::OMPD_parallel),
333     "SINGLE" >> pure(llvm::omp::Directive::OMPD_single),
334     "TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data),
335     "TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel),
336     "TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams),
337     "TARGET" >> pure(llvm::omp::Directive::OMPD_target),
338     "TASK"_id >> pure(llvm::omp::Directive::OMPD_task),
339     "TASKGROUP" >> pure(llvm::omp::Directive::OMPD_taskgroup),
340     "TEAMS" >> pure(llvm::omp::Directive::OMPD_teams),
341     "WORKSHARE" >> pure(llvm::omp::Directive::OMPD_workshare))))
342 
343 TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>(
344     sourced(Parser<OmpBlockDirective>{}), Parser<OmpClauseList>{})))
345 
346 TYPE_PARSER(construct<OmpReductionInitializerClause>(
347     "INITIALIZER" >> parenthesized("OMP_PRIV =" >> expr)))
348 
349 // 2.16 Declare Reduction Construct
350 TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
351     verbatim("DECLARE REDUCTION"_tok),
352     "(" >> Parser<OmpReductionOperator>{} / ":",
353     nonemptyList(Parser<DeclarationTypeSpec>{}) / ":",
354     Parser<OmpReductionCombiner>{} / ")",
355     maybe(Parser<OmpReductionInitializerClause>{}))))
356 
357 // declare-target with list
358 TYPE_PARSER(sourced(construct<OmpDeclareTargetWithList>(
359     parenthesized(Parser<OmpObjectList>{}))))
360 
361 // declare-target with clause
362 TYPE_PARSER(
363     sourced(construct<OmpDeclareTargetWithClause>(Parser<OmpClauseList>{})))
364 
365 // declare-target-specifier
366 TYPE_PARSER(
367     construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithList>{}) ||
368     construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithClause>{}))
369 
370 // 2.10.6 Declare Target Construct
371 TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
372     verbatim("DECLARE TARGET"_tok), Parser<OmpDeclareTargetSpecifier>{})))
373 
374 TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) ||
375     construct<OmpReductionCombiner>(
376         construct<OmpReductionCombiner::FunctionCombiner>(
377             construct<Call>(Parser<ProcedureDesignator>{},
378                 parenthesized(optionalList(actualArgSpec))))))
379 
380 // 2.13.6 ATOMIC [seq_cst[,]] atomic-clause [[,]seq_cst] | ATOMIC [seq_cst]
381 //        atomic-clause -> READ | WRITE | UPDATE | CAPTURE
382 
383 // OMP END ATOMIC
384 TYPE_PARSER(construct<OmpEndAtomic>(startOmpLine >> "END ATOMIC"_tok))
385 
386 // ATOMIC Memory related clause
387 TYPE_PARSER(sourced(construct<OmpMemoryClause>(
388     "SEQ_CST" >> pure(OmpMemoryClause::MemoryOrder::SeqCst))))
389 
390 // ATOMIC Memory Clause List
391 TYPE_PARSER(construct<OmpMemoryClauseList>(
392     many(maybe(","_tok) >> Parser<OmpMemoryClause>{})))
393 
394 TYPE_PARSER(construct<OmpMemoryClausePostList>(
395     many(maybe(","_tok) >> Parser<OmpMemoryClause>{})))
396 
397 // OMP [SEQ_CST] ATOMIC READ [SEQ_CST]
398 TYPE_PARSER("ATOMIC" >>
399     construct<OmpAtomicRead>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
400         verbatim("READ"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
401         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
402 
403 // OMP ATOMIC [SEQ_CST] CAPTURE [SEQ_CST]
404 TYPE_PARSER("ATOMIC" >>
405     construct<OmpAtomicCapture>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
406         verbatim("CAPTURE"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
407         statement(assignmentStmt), statement(assignmentStmt),
408         Parser<OmpEndAtomic>{} / endOmpLine))
409 
410 // OMP ATOMIC [SEQ_CST] UPDATE [SEQ_CST]
411 TYPE_PARSER("ATOMIC" >>
412     construct<OmpAtomicUpdate>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
413         verbatim("UPDATE"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
414         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
415 
416 // OMP ATOMIC [SEQ_CST]
417 TYPE_PARSER(construct<OmpAtomic>(verbatim("ATOMIC"_tok),
418     Parser<OmpMemoryClauseList>{} / endOmpLine, statement(assignmentStmt),
419     maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
420 
421 // ATOMIC [SEQ_CST] WRITE [SEQ_CST]
422 TYPE_PARSER("ATOMIC" >>
423     construct<OmpAtomicWrite>(Parser<OmpMemoryClauseList>{} / maybe(","_tok),
424         verbatim("WRITE"_tok), Parser<OmpMemoryClausePostList>{} / endOmpLine,
425         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
426 
427 // Atomic Construct
428 TYPE_PARSER(construct<OpenMPAtomicConstruct>(Parser<OmpAtomicRead>{}) ||
429     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCapture>{}) ||
430     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicWrite>{}) ||
431     construct<OpenMPAtomicConstruct>(Parser<OmpAtomicUpdate>{}) ||
432     construct<OpenMPAtomicConstruct>(Parser<OmpAtomic>{}))
433 
434 // 2.13.2 OMP CRITICAL
435 TYPE_PARSER(startOmpLine >>
436     sourced(construct<OmpEndCriticalDirective>(
437         verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) /
438         endOmpLine)
439 TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok),
440                 maybe(parenthesized(name)),
441                 maybe("HINT" >> construct<OmpCriticalDirective::Hint>(
442                                     parenthesized(constantExpr))))) /
443     endOmpLine)
444 
445 TYPE_PARSER(construct<OpenMPCriticalConstruct>(
446     Parser<OmpCriticalDirective>{}, block, Parser<OmpEndCriticalDirective>{}))
447 
448 // 2.8.2 Declare Simd construct
449 TYPE_PARSER(
450     sourced(construct<OpenMPDeclareSimdConstruct>(verbatim("DECLARE SIMD"_tok),
451         maybe(parenthesized(name)), Parser<OmpClauseList>{})))
452 
453 // 2.15.2 Threadprivate directive
454 TYPE_PARSER(sourced(construct<OpenMPThreadprivate>(
455     verbatim("THREADPRIVATE"_tok), parenthesized(Parser<OmpObjectList>{}))))
456 
457 // Declarative constructs
458 TYPE_PARSER(startOmpLine >>
459     sourced(construct<OpenMPDeclarativeConstruct>(
460                 Parser<OpenMPDeclareReductionConstruct>{}) ||
461         construct<OpenMPDeclarativeConstruct>(
462             Parser<OpenMPDeclareSimdConstruct>{}) ||
463         construct<OpenMPDeclarativeConstruct>(
464             Parser<OpenMPDeclareTargetConstruct>{}) ||
465         construct<OpenMPDeclarativeConstruct>(Parser<OpenMPThreadprivate>{})) /
466         endOmpLine)
467 
468 // Block Construct
469 TYPE_PARSER(construct<OpenMPBlockConstruct>(
470     Parser<OmpBeginBlockDirective>{} / endOmpLine, block,
471     Parser<OmpEndBlockDirective>{} / endOmpLine))
472 
473 // OMP SECTIONS Directive
474 TYPE_PARSER(construct<OmpSectionsDirective>(first(
475     "SECTIONS" >> pure(llvm::omp::Directive::OMPD_sections),
476     "PARALLEL SECTIONS" >> pure(llvm::omp::Directive::OMPD_parallel_sections))))
477 
478 // OMP BEGIN and END SECTIONS Directive
479 TYPE_PARSER(sourced(construct<OmpBeginSectionsDirective>(
480     sourced(Parser<OmpSectionsDirective>{}), Parser<OmpClauseList>{})))
481 TYPE_PARSER(
482     startOmpLine >> sourced(construct<OmpEndSectionsDirective>(
483                         sourced("END"_tok >> Parser<OmpSectionsDirective>{}),
484                         Parser<OmpClauseList>{})))
485 
486 // OMP SECTION-BLOCK
487 TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >>
488     construct<OmpSectionBlocks>(
489         nonemptySeparated(block, startOmpLine >> "SECTION"_tok / endOmpLine)))
490 
491 // OMP SECTIONS (2.7.2), PARALLEL SECTIONS (2.11.2)
492 TYPE_PARSER(construct<OpenMPSectionsConstruct>(
493     Parser<OmpBeginSectionsDirective>{} / endOmpLine,
494     Parser<OmpSectionBlocks>{}, Parser<OmpEndSectionsDirective>{} / endOmpLine))
495 
496 TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
497     startOmpLine >>
498         first(construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}),
499             construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}),
500             construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}),
501             // OpenMPBlockConstruct is attempted before
502             // OpenMPStandaloneConstruct to resolve !$OMP ORDERED
503             construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}),
504             construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}),
505             construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{})))
506 
507 // END OMP Block directives
508 TYPE_PARSER(
509     startOmpLine >> sourced(construct<OmpEndBlockDirective>(
510                         sourced("END"_tok >> Parser<OmpBlockDirective>{}),
511                         Parser<OmpClauseList>{})))
512 
513 // END OMP Loop directives
514 TYPE_PARSER(
515     startOmpLine >> sourced(construct<OmpEndLoopDirective>(
516                         sourced("END"_tok >> Parser<OmpLoopDirective>{}),
517                         Parser<OmpClauseList>{})))
518 
519 TYPE_PARSER(construct<OpenMPLoopConstruct>(
520     Parser<OmpBeginLoopDirective>{} / endOmpLine))
521 } // namespace Fortran::parser
522