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#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/ADT/StringSet.h"
23#include "llvm/Frontend/OpenMP/OMP.h"
24
25// OpenMP Directives and Clauses
26namespace Fortran::parser {
27
28// Helper function to print the buffer contents starting at the current point.
29[[maybe_unused]] static std::string ahead(const ParseState &state) {
30 return std::string(
31 state.GetLocation(), std::min<size_t>(64, state.BytesRemaining()));
32}
33
34constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok;
35constexpr auto endOmpLine = space >> endOfLine;
36
37// Given a parser P for a wrapper class, invoke P, and if it succeeds return
38// the wrapped object.
39template <typename Parser> struct UnwrapParser {
40 static_assert(
41 Parser::resultType::WrapperTrait::value && "Wrapper class required");
42 using resultType = decltype(Parser::resultType::v);
43 constexpr UnwrapParser(Parser p) : parser_(p) {}
44
45 std::optional<resultType> Parse(ParseState &state) const {
46 if (auto result{parser_.Parse(state)}) {
47 return result->v;
48 }
49 return std::nullopt;
50 }
51
52private:
53 const Parser parser_;
54};
55
56template <typename Parser> constexpr auto unwrap(const Parser &p) {
57 return UnwrapParser<Parser>(p);
58}
59
60// Check (without advancing the parsing location) if the next thing in the
61// input would be accepted by the "checked" parser, and if so, run the "parser"
62// parser.
63// The intended use is with the "checker" parser being some token, followed
64// by a more complex parser that consumes the token plus more things, e.g.
65// "PARALLEL"_id >= Parser<OmpDirectiveSpecification>{}.
66//
67// The >= has a higher precedence than ||, so it can be used just like >>
68// in an alternatives parser without parentheses.
69template <typename PA, typename PB>
70constexpr auto operator>=(PA checker, PB parser) {
71 return lookAhead(checker) >> parser;
72}
73
74// This parser succeeds if the given parser succeeds, and the result
75// satisfies the given condition. Specifically, it succeeds if:
76// 1. The parser given as the argument succeeds, and
77// 2. The condition function (called with PA::resultType) returns true
78// for the result.
79template <typename PA, typename CF> struct PredicatedParser {
80 using resultType = typename PA::resultType;
81
82 constexpr PredicatedParser(PA parser, CF condition)
83 : parser_(parser), condition_(condition) {}
84
85 std::optional<resultType> Parse(ParseState &state) const {
86 if (auto result{parser_.Parse(state)}; result && condition_(*result)) {
87 return result;
88 }
89 return std::nullopt;
90 }
91
92private:
93 const PA parser_;
94 const CF condition_;
95};
96
97template <typename PA, typename CF>
98constexpr auto predicated(PA parser, CF condition) {
99 return PredicatedParser(parser, condition);
100}
101
102/// Parse OpenMP directive name (this includes compound directives).
103struct OmpDirectiveNameParser {
104 using resultType = OmpDirectiveName;
105 using Token = TokenStringMatch<false, false>;
106
107 std::optional<resultType> Parse(ParseState &state) const {
108 if (state.BytesRemaining() == 0) {
109 return std::nullopt;
110 }
111 auto begin{state.GetLocation()};
112 char next{static_cast<char>(std::tolower(*begin))};
113
114 for (const NameWithId &nid : directives_starting_with(next)) {
115 if (attempt(Token(nid.first.data())).Parse(state)) {
116 OmpDirectiveName n;
117 n.v = nid.second;
118 n.source = parser::CharBlock(begin, state.GetLocation());
119 return n;
120 }
121 }
122 return std::nullopt;
123 }
124
125private:
126 using NameWithId = std::pair<std::string, llvm::omp::Directive>;
127 using ConstIterator = std::vector<NameWithId>::const_iterator;
128
129 llvm::iterator_range<ConstIterator> directives_starting_with(
130 char initial) const;
131 void initTokens(std::vector<NameWithId>[]) const;
132};
133
134llvm::iterator_range<OmpDirectiveNameParser::ConstIterator>
135OmpDirectiveNameParser::directives_starting_with(char initial) const {
136 static const std::vector<NameWithId> empty{};
137 if (initial < 'a' || initial > 'z') {
138 return llvm::make_range(x: std::cbegin(cont: empty), y: std::cend(cont: empty));
139 }
140
141 static std::vector<NameWithId> table['z' - 'a' + 1];
142 [[maybe_unused]] static bool init = (initTokens(table), true);
143
144 int index = initial - 'a';
145 return llvm::make_range(x: std::cbegin(cont: table[index]), y: std::cend(cont: table[index]));
146}
147
148void OmpDirectiveNameParser::initTokens(std::vector<NameWithId> table[]) const {
149 for (size_t i{0}, e{llvm::omp::Directive_enumSize}; i != e; ++i) {
150 llvm::StringSet spellings;
151 auto id{static_cast<llvm::omp::Directive>(i)};
152 for (unsigned version : llvm::omp::getOpenMPVersions()) {
153 spellings.insert(key: llvm::omp::getOpenMPDirectiveName(D: id, Ver: version));
154 }
155 for (auto &[name, _] : spellings) {
156 char initial{static_cast<char>(std::tolower(c: name.front()))};
157 table[initial - 'a'].emplace_back(args: name.str(), args&: id);
158 }
159 }
160 // Sort the table with respect to the directive name length in a descending
161 // order. This is to make sure that longer names are tried first, before
162 // any potential prefix (e.g. "target update" before "target").
163 for (int initial{'a'}; initial != 'z' + 1; ++initial) {
164 llvm::stable_sort(Range&: table[initial - 'a'],
165 C: [](auto &a, auto &b) { return a.first.size() > b.first.size(); });
166 }
167}
168
169// --- Modifier helpers -----------------------------------------------
170
171template <typename Clause, typename Separator> struct ModifierList {
172 constexpr ModifierList(Separator sep) : sep_(sep) {}
173 constexpr ModifierList(const ModifierList &) = default;
174 constexpr ModifierList(ModifierList &&) = default;
175
176 using resultType = std::list<typename Clause::Modifier>;
177
178 std::optional<resultType> Parse(ParseState &state) const {
179 auto listp{nonemptySeparated(Parser<typename Clause::Modifier>{}, sep_)};
180 if (auto result{attempt(listp).Parse(state)}) {
181 if (!attempt(":"_tok).Parse(state)) {
182 return std::nullopt;
183 }
184 return std::move(result);
185 }
186 return resultType{};
187 }
188
189private:
190 const Separator sep_;
191};
192
193// Use a function to create ModifierList because functions allow "partial"
194// template argument deduction: "modifierList<Clause>(sep)" would be legal,
195// while "ModifierList<Clause>(sep)" would complain about a missing template
196// argument "Separator".
197template <typename Clause, typename Separator>
198constexpr ModifierList<Clause, Separator> modifierList(Separator sep) {
199 return ModifierList<Clause, Separator>(sep);
200}
201
202// Parse the input as any modifier from ClauseTy, but only succeed if
203// the result was the SpecificTy. It requires that SpecificTy is one
204// of the alternatives in ClauseTy::Modifier.
205// The reason to have this is that ClauseTy::Modifier has "source",
206// while specific modifiers don't. This class allows to parse a specific
207// modifier together with obtaining its location.
208template <typename SpecificTy, typename ClauseTy>
209struct SpecificModifierParser {
210 using resultType = typename ClauseTy::Modifier;
211 std::optional<resultType> Parse(ParseState &state) const {
212 if (auto result{attempt(Parser<resultType>{}).Parse(state)}) {
213 if (std::holds_alternative<SpecificTy>(result->u)) {
214 return result;
215 }
216 }
217 return std::nullopt;
218 }
219};
220
221// --- Iterator helpers -----------------------------------------------
222
223// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not
224// specified then the type of that iterator is default integer.
225// [5.0:49:14] The iterator-type must be an integer type.
226static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) {
227 std::list<EntityDecl> entities;
228
229 for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) {
230 EntityDecl entityDecl(
231 /*ObjectName=*/std::move(*iter), std::optional<ArraySpec>{},
232 std::optional<CoarraySpec>{}, std::optional<CharLength>{},
233 std::optional<Initialization>{});
234 entities.push_back(std::move(entityDecl));
235 }
236 return entities;
237}
238
239static TypeDeclarationStmt makeIterSpecDecl(
240 DeclarationTypeSpec &&spec, std::list<ObjectName> &&names) {
241 return TypeDeclarationStmt(
242 std::move(spec), std::list<AttrSpec>{}, makeEntityList(std::move(names)));
243}
244
245static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
246 // Assume INTEGER without kind selector.
247 DeclarationTypeSpec typeSpec(
248 IntrinsicTypeSpec{IntegerTypeSpec{std::nullopt}});
249
250 return TypeDeclarationStmt(std::move(typeSpec), std::list<AttrSpec>{},
251 makeEntityList(std::move(names)));
252}
253
254// --- Parsers for arguments ------------------------------------------
255
256// At the moment these are only directive arguments. This is needed for
257// parsing directive-specification.
258
259TYPE_PARSER( //
260 construct<OmpLocator>(Parser<OmpObject>{}) ||
261 construct<OmpLocator>(Parser<FunctionReference>{}))
262
263TYPE_PARSER(sourced( //
264 construct<OmpArgument>(Parser<OmpMapperSpecifier>{}) ||
265 construct<OmpArgument>(Parser<OmpReductionSpecifier>{}) ||
266 construct<OmpArgument>(Parser<OmpLocator>{})))
267
268TYPE_PARSER(construct<OmpLocatorList>(nonemptyList(Parser<OmpLocator>{})))
269
270TYPE_PARSER(sourced( //
271 construct<OmpArgumentList>(nonemptyList(Parser<OmpArgument>{}))))
272
273TYPE_PARSER( //
274 construct<OmpTypeSpecifier>(Parser<DeclarationTypeSpec>{}) ||
275 construct<OmpTypeSpecifier>(Parser<TypeSpec>{}))
276
277TYPE_PARSER(construct<OmpReductionSpecifier>( //
278 Parser<OmpReductionIdentifier>{},
279 ":"_tok >> nonemptyList(Parser<OmpTypeSpecifier>{}),
280 maybe(":"_tok >> Parser<OmpReductionCombiner>{})))
281
282// --- Parsers for context traits -------------------------------------
283
284static std::string nameToString(Name &&name) { return name.ToString(); }
285
286TYPE_PARSER(sourced(construct<OmpTraitPropertyName>( //
287 construct<OmpTraitPropertyName>(space >> charLiteralConstantWithoutKind) ||
288 construct<OmpTraitPropertyName>(
289 applyFunction(nameToString, Parser<Name>{})))))
290
291TYPE_PARSER(sourced(construct<OmpTraitScore>( //
292 "SCORE"_id >> parenthesized(scalarIntExpr))))
293
294TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension::Complex>(
295 Parser<OmpTraitPropertyName>{},
296 parenthesized(nonemptySeparated(
297 indirect(Parser<OmpTraitPropertyExtension>{}), ",")))))
298
299TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension>(
300 construct<OmpTraitPropertyExtension>(
301 Parser<OmpTraitPropertyExtension::Complex>{}) ||
302 construct<OmpTraitPropertyExtension>(Parser<OmpTraitPropertyName>{}) ||
303 construct<OmpTraitPropertyExtension>(scalarExpr))))
304
305TYPE_PARSER(construct<OmpTraitSelectorName::Value>(
306 "ARCH"_id >> pure(OmpTraitSelectorName::Value::Arch) ||
307 "ATOMIC_DEFAULT_MEM_ORDER"_id >>
308 pure(OmpTraitSelectorName::Value::Atomic_Default_Mem_Order) ||
309 "CONDITION"_id >> pure(OmpTraitSelectorName::Value::Condition) ||
310 "DEVICE_NUM"_id >> pure(OmpTraitSelectorName::Value::Device_Num) ||
311 "EXTENSION"_id >> pure(OmpTraitSelectorName::Value::Extension) ||
312 "ISA"_id >> pure(OmpTraitSelectorName::Value::Isa) ||
313 "KIND"_id >> pure(OmpTraitSelectorName::Value::Kind) ||
314 "REQUIRES"_id >> pure(OmpTraitSelectorName::Value::Requires) ||
315 "SIMD"_id >> pure(OmpTraitSelectorName::Value::Simd) ||
316 "UID"_id >> pure(OmpTraitSelectorName::Value::Uid) ||
317 "VENDOR"_id >> pure(OmpTraitSelectorName::Value::Vendor)))
318
319TYPE_PARSER(sourced(construct<OmpTraitSelectorName>(
320 // Parse predefined names first (because of SIMD).
321 construct<OmpTraitSelectorName>(Parser<OmpTraitSelectorName::Value>{}) ||
322 construct<OmpTraitSelectorName>(unwrap(OmpDirectiveNameParser{})) ||
323 // identifier-or-string for extensions
324 construct<OmpTraitSelectorName>(
325 applyFunction(nameToString, Parser<Name>{})) ||
326 construct<OmpTraitSelectorName>(space >> charLiteralConstantWithoutKind))))
327
328// Parser for OmpTraitSelector::Properties
329template <typename... PropParser>
330static constexpr auto propertyListParser(PropParser... pp) {
331 // Parse the property list "(score(expr): item1...)" in three steps:
332 // 1. Parse the "("
333 // 2. Parse the optional "score(expr):"
334 // 3. Parse the "item1, ...)", together with the ")".
335 // The reason for including the ")" in the 3rd step is to force parsing
336 // the entire list in each of the alternative property parsers. Otherwise,
337 // the name parser could stop after "foo" in "(foo, bar(1))", without
338 // allowing the next parser to give the list a try.
339 using P = OmpTraitProperty;
340 return maybe("(" >> //
341 construct<OmpTraitSelector::Properties>(
342 maybe(Parser<OmpTraitScore>{} / ":"),
343 (attempt(nonemptyList(sourced(construct<P>(pp))) / ")") || ...)));
344}
345
346// Parser for OmpTraitSelector
347struct TraitSelectorParser {
348 using resultType = OmpTraitSelector;
349
350 constexpr TraitSelectorParser(Parser<OmpTraitSelectorName> p) : np(p) {}
351
352 std::optional<resultType> Parse(ParseState &state) const {
353 auto name{attempt(np).Parse(state)};
354 if (!name.has_value()) {
355 return std::nullopt;
356 }
357
358 // Default fallback parser for lists that cannot be parser using the
359 // primary property parser.
360 auto extParser{Parser<OmpTraitPropertyExtension>{}};
361
362 if (auto *v{std::get_if<OmpTraitSelectorName::Value>(&name->u)}) {
363 // (*) The comments below show the sections of the OpenMP spec that
364 // describe given trait. The cases marked with a (*) are those where
365 // the spec doesn't assign any list-type to these traits, but for
366 // convenience they can be treated as if they were.
367 switch (*v) {
368 // name-list properties
369 case OmpTraitSelectorName::Value::Arch: // [6.0:319:18]
370 case OmpTraitSelectorName::Value::Extension: // [6.0:319:30]
371 case OmpTraitSelectorName::Value::Isa: // [6.0:319:15]
372 case OmpTraitSelectorName::Value::Kind: // [6.0:319:10]
373 case OmpTraitSelectorName::Value::Uid: // [6.0:319:23](*)
374 case OmpTraitSelectorName::Value::Vendor: { // [6.0:319:27]
375 auto pp{propertyListParser(Parser<OmpTraitPropertyName>{}, extParser)};
376 return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
377 }
378 // clause-list
379 case OmpTraitSelectorName::Value::Atomic_Default_Mem_Order:
380 // [6.0:321:26-29](*)
381 case OmpTraitSelectorName::Value::Requires: // [6.0:319:33]
382 case OmpTraitSelectorName::Value::Simd: { // [6.0:318:31]
383 auto pp{propertyListParser(indirect(Parser<OmpClause>{}), extParser)};
384 return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
385 }
386 // expr-list
387 case OmpTraitSelectorName::Value::Condition: // [6.0:321:33](*)
388 case OmpTraitSelectorName::Value::Device_Num: { // [6.0:321:23-24](*)
389 auto pp{propertyListParser(scalarExpr, extParser)};
390 return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
391 }
392 } // switch
393 } else {
394 // The other alternatives are `llvm::omp::Directive`, and `std::string`.
395 // The former doesn't take any properties[1], the latter is a name of an
396 // extension[2].
397 // [1] [6.0:319:1-2]
398 // [2] [6.0:319:36-37]
399 auto pp{propertyListParser(extParser)};
400 return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
401 }
402
403 llvm_unreachable("Unhandled trait name?");
404 }
405
406private:
407 const Parser<OmpTraitSelectorName> np;
408};
409
410TYPE_PARSER(sourced(construct<OmpTraitSelector>(
411 sourced(TraitSelectorParser(Parser<OmpTraitSelectorName>{})))))
412
413TYPE_PARSER(construct<OmpTraitSetSelectorName::Value>(
414 "CONSTRUCT"_id >> pure(OmpTraitSetSelectorName::Value::Construct) ||
415 "DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Device) ||
416 "IMPLEMENTATION"_id >>
417 pure(OmpTraitSetSelectorName::Value::Implementation) ||
418 "TARGET_DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Target_Device) ||
419 "USER"_id >> pure(OmpTraitSetSelectorName::Value::User)))
420
421TYPE_PARSER(sourced(construct<OmpTraitSetSelectorName>(
422 Parser<OmpTraitSetSelectorName::Value>{})))
423
424TYPE_PARSER(sourced(construct<OmpTraitSetSelector>( //
425 Parser<OmpTraitSetSelectorName>{},
426 "=" >> braced(nonemptySeparated(Parser<OmpTraitSelector>{}, ",")))))
427
428TYPE_PARSER(sourced(construct<OmpContextSelectorSpecification>(
429 nonemptySeparated(Parser<OmpTraitSetSelector>{}, ","))))
430
431// Note: OmpContextSelector is a type alias.
432
433// --- Parsers for clause modifiers -----------------------------------
434
435TYPE_PARSER(construct<OmpAlignment>(scalarIntExpr))
436
437TYPE_PARSER(construct<OmpAlignModifier>( //
438 "ALIGN" >> parenthesized(scalarIntExpr)))
439
440TYPE_PARSER(construct<OmpAllocatorComplexModifier>(
441 "ALLOCATOR" >> parenthesized(scalarIntExpr)))
442
443TYPE_PARSER(construct<OmpAllocatorSimpleModifier>(scalarIntExpr))
444
445TYPE_PARSER(construct<OmpChunkModifier>( //
446 "SIMD" >> pure(OmpChunkModifier::Value::Simd)))
447
448TYPE_PARSER(construct<OmpDependenceType>(
449 "SINK" >> pure(OmpDependenceType::Value::Sink) ||
450 "SOURCE" >> pure(OmpDependenceType::Value::Source)))
451
452TYPE_PARSER(construct<OmpDeviceModifier>(
453 "ANCESTOR" >> pure(OmpDeviceModifier::Value::Ancestor) ||
454 "DEVICE_NUM" >> pure(OmpDeviceModifier::Value::Device_Num)))
455
456TYPE_PARSER(construct<OmpExpectation>( //
457 "PRESENT" >> pure(OmpExpectation::Value::Present)))
458
459TYPE_PARSER(construct<OmpInteropRuntimeIdentifier>(
460 construct<OmpInteropRuntimeIdentifier>(charLiteralConstant) ||
461 construct<OmpInteropRuntimeIdentifier>(scalarIntConstantExpr)))
462
463TYPE_PARSER(construct<OmpInteropPreference>(verbatim("PREFER_TYPE"_tok) >>
464 parenthesized(nonemptyList(Parser<OmpInteropRuntimeIdentifier>{}))))
465
466TYPE_PARSER(construct<OmpInteropType>(
467 "TARGETSYNC" >> pure(OmpInteropType::Value::TargetSync) ||
468 "TARGET" >> pure(OmpInteropType::Value::Target)))
469
470TYPE_PARSER(construct<OmpIteratorSpecifier>(
471 // Using Parser<TypeDeclarationStmt> or Parser<EntityDecl> has the problem
472 // that they will attempt to treat what follows the '=' as initialization.
473 // There are several issues with that,
474 // 1. integer :: i = 0:10 will be parsed as "integer :: i = 0", followed
475 // by triplet ":10".
476 // 2. integer :: j = i:10 will be flagged as an error because the
477 // initializer 'i' must be constant (in declarations). In an iterator
478 // specifier the 'j' is not an initializer and can be a variable.
479 (applyFunction<TypeDeclarationStmt>(makeIterSpecDecl,
480 Parser<DeclarationTypeSpec>{} / maybe("::"_tok),
481 nonemptyList(Parser<ObjectName>{}) / "="_tok) ||
482 applyFunction<TypeDeclarationStmt>(
483 makeIterSpecDecl, nonemptyList(Parser<ObjectName>{}) / "="_tok)),
484 subscriptTriplet))
485
486// [5.0] 2.1.6 iterator -> iterator-specifier-list
487TYPE_PARSER(construct<OmpIterator>( //
488 "ITERATOR" >>
489 parenthesized(nonemptyList(sourced(Parser<OmpIteratorSpecifier>{})))))
490
491TYPE_PARSER(construct<OmpLastprivateModifier>(
492 "CONDITIONAL" >> pure(OmpLastprivateModifier::Value::Conditional)))
493
494// 2.15.3.7 LINEAR (linear-list: linear-step)
495// linear-list -> list | modifier(list)
496// linear-modifier -> REF | VAL | UVAL
497TYPE_PARSER(construct<OmpLinearModifier>( //
498 "REF" >> pure(OmpLinearModifier::Value::Ref) ||
499 "VAL" >> pure(OmpLinearModifier::Value::Val) ||
500 "UVAL" >> pure(OmpLinearModifier::Value::Uval)))
501
502TYPE_PARSER(construct<OmpMapper>( //
503 "MAPPER"_tok >> parenthesized(Parser<ObjectName>{})))
504
505// map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM
506TYPE_PARSER(construct<OmpMapType>( //
507 "ALLOC" >> pure(OmpMapType::Value::Alloc) ||
508 "DELETE" >> pure(OmpMapType::Value::Delete) ||
509 "FROM" >> pure(OmpMapType::Value::From) ||
510 "RELEASE" >> pure(OmpMapType::Value::Release) ||
511 "TO"_id >> pure(OmpMapType::Value::To) ||
512 "TOFROM" >> pure(OmpMapType::Value::Tofrom)))
513
514// map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT
515TYPE_PARSER(construct<OmpMapTypeModifier>(
516 "ALWAYS" >> pure(OmpMapTypeModifier::Value::Always) ||
517 "CLOSE" >> pure(OmpMapTypeModifier::Value::Close) ||
518 "OMPX_HOLD" >> pure(OmpMapTypeModifier::Value::Ompx_Hold) ||
519 "PRESENT" >> pure(OmpMapTypeModifier::Value::Present)))
520
521// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
522TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||
523 construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))
524
525TYPE_PARSER(construct<OmpOrderModifier>(
526 "REPRODUCIBLE" >> pure(OmpOrderModifier::Value::Reproducible) ||
527 "UNCONSTRAINED" >> pure(OmpOrderModifier::Value::Unconstrained)))
528
529TYPE_PARSER(construct<OmpOrderingModifier>(
530 "MONOTONIC" >> pure(OmpOrderingModifier::Value::Monotonic) ||
531 "NONMONOTONIC" >> pure(OmpOrderingModifier::Value::Nonmonotonic) ||
532 "SIMD" >> pure(OmpOrderingModifier::Value::Simd)))
533
534TYPE_PARSER(construct<OmpPrescriptiveness>(
535 "STRICT" >> pure(OmpPrescriptiveness::Value::Strict)))
536
537TYPE_PARSER(construct<OmpReductionModifier>(
538 "INSCAN" >> pure(OmpReductionModifier::Value::Inscan) ||
539 "TASK" >> pure(OmpReductionModifier::Value::Task) ||
540 "DEFAULT" >> pure(OmpReductionModifier::Value::Default)))
541
542TYPE_PARSER(construct<OmpStepComplexModifier>( //
543 "STEP" >> parenthesized(scalarIntExpr)))
544
545TYPE_PARSER(construct<OmpStepSimpleModifier>(scalarIntExpr))
546
547TYPE_PARSER(construct<OmpTaskDependenceType>(
548 "DEPOBJ" >> pure(OmpTaskDependenceType::Value::Depobj) ||
549 "IN"_id >> pure(OmpTaskDependenceType::Value::In) ||
550 "INOUT"_id >> pure(OmpTaskDependenceType::Value::Inout) ||
551 "INOUTSET"_id >> pure(OmpTaskDependenceType::Value::Inoutset) ||
552 "MUTEXINOUTSET" >> pure(OmpTaskDependenceType::Value::Mutexinoutset) ||
553 "OUT" >> pure(OmpTaskDependenceType::Value::Out)))
554
555TYPE_PARSER(construct<OmpVariableCategory>(
556 "AGGREGATE" >> pure(OmpVariableCategory::Value::Aggregate) ||
557 "ALL"_id >> pure(OmpVariableCategory::Value::All) ||
558 "ALLOCATABLE" >> pure(OmpVariableCategory::Value::Allocatable) ||
559 "POINTER" >> pure(OmpVariableCategory::Value::Pointer) ||
560 "SCALAR" >> pure(OmpVariableCategory::Value::Scalar)))
561
562// This could be auto-generated.
563TYPE_PARSER(
564 sourced(construct<OmpAffinityClause::Modifier>(Parser<OmpIterator>{})))
565
566TYPE_PARSER(
567 sourced(construct<OmpAlignedClause::Modifier>(Parser<OmpAlignment>{})))
568
569TYPE_PARSER(sourced(construct<OmpAllocateClause::Modifier>(sourced(
570 construct<OmpAllocateClause::Modifier>(Parser<OmpAlignModifier>{}) ||
571 construct<OmpAllocateClause::Modifier>(
572 Parser<OmpAllocatorComplexModifier>{}) ||
573 construct<OmpAllocateClause::Modifier>(
574 Parser<OmpAllocatorSimpleModifier>{})))))
575
576TYPE_PARSER(sourced(
577 construct<OmpDefaultmapClause::Modifier>(Parser<OmpVariableCategory>{})))
578
579TYPE_PARSER(sourced(construct<OmpDependClause::TaskDep::Modifier>(sourced(
580 construct<OmpDependClause::TaskDep::Modifier>(Parser<OmpIterator>{}) ||
581 construct<OmpDependClause::TaskDep::Modifier>(
582 Parser<OmpTaskDependenceType>{})))))
583
584TYPE_PARSER(
585 sourced(construct<OmpDeviceClause::Modifier>(Parser<OmpDeviceModifier>{})))
586
587TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>(
588 sourced(construct<OmpFromClause::Modifier>(Parser<OmpExpectation>{}) ||
589 construct<OmpFromClause::Modifier>(Parser<OmpMapper>{}) ||
590 construct<OmpFromClause::Modifier>(Parser<OmpIterator>{})))))
591
592TYPE_PARSER(sourced(
593 construct<OmpGrainsizeClause::Modifier>(Parser<OmpPrescriptiveness>{})))
594
595TYPE_PARSER(sourced(construct<OmpIfClause::Modifier>(OmpDirectiveNameParser{})))
596
597TYPE_PARSER(sourced(
598 construct<OmpInitClause::Modifier>(
599 construct<OmpInitClause::Modifier>(Parser<OmpInteropPreference>{})) ||
600 construct<OmpInitClause::Modifier>(Parser<OmpInteropType>{})))
601
602TYPE_PARSER(sourced(construct<OmpInReductionClause::Modifier>(
603 Parser<OmpReductionIdentifier>{})))
604
605TYPE_PARSER(sourced(construct<OmpLastprivateClause::Modifier>(
606 Parser<OmpLastprivateModifier>{})))
607
608TYPE_PARSER(sourced(
609 construct<OmpLinearClause::Modifier>(Parser<OmpLinearModifier>{}) ||
610 construct<OmpLinearClause::Modifier>(Parser<OmpStepComplexModifier>{}) ||
611 construct<OmpLinearClause::Modifier>(Parser<OmpStepSimpleModifier>{})))
612
613TYPE_PARSER(sourced(construct<OmpMapClause::Modifier>(
614 sourced(construct<OmpMapClause::Modifier>(Parser<OmpMapTypeModifier>{}) ||
615 construct<OmpMapClause::Modifier>(Parser<OmpMapper>{}) ||
616 construct<OmpMapClause::Modifier>(Parser<OmpIterator>{}) ||
617 construct<OmpMapClause::Modifier>(Parser<OmpMapType>{})))))
618
619TYPE_PARSER(
620 sourced(construct<OmpOrderClause::Modifier>(Parser<OmpOrderModifier>{})))
621
622TYPE_PARSER(sourced(
623 construct<OmpNumTasksClause::Modifier>(Parser<OmpPrescriptiveness>{})))
624
625TYPE_PARSER(sourced(construct<OmpReductionClause::Modifier>(sourced(
626 construct<OmpReductionClause::Modifier>(Parser<OmpReductionModifier>{}) ||
627 construct<OmpReductionClause::Modifier>(
628 Parser<OmpReductionIdentifier>{})))))
629
630TYPE_PARSER(sourced(construct<OmpScheduleClause::Modifier>(sourced(
631 construct<OmpScheduleClause::Modifier>(Parser<OmpChunkModifier>{}) ||
632 construct<OmpScheduleClause::Modifier>(Parser<OmpOrderingModifier>{})))))
633
634TYPE_PARSER(sourced(construct<OmpTaskReductionClause::Modifier>(
635 Parser<OmpReductionIdentifier>{})))
636
637TYPE_PARSER(sourced(construct<OmpToClause::Modifier>(
638 sourced(construct<OmpToClause::Modifier>(Parser<OmpExpectation>{}) ||
639 construct<OmpToClause::Modifier>(Parser<OmpMapper>{}) ||
640 construct<OmpToClause::Modifier>(Parser<OmpIterator>{})))))
641
642TYPE_PARSER(sourced(construct<OmpWhenClause::Modifier>( //
643 Parser<OmpContextSelector>{})))
644
645TYPE_PARSER(construct<OmpAppendArgsClause::OmpAppendOp>(
646 "INTEROP" >> parenthesized(nonemptyList(Parser<OmpInteropType>{}))))
647
648TYPE_PARSER(construct<OmpAdjustArgsClause::OmpAdjustOp>(
649 "NOTHING" >> pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Nothing) ||
650 "NEED_DEVICE_PTR" >>
651 pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Need_Device_Ptr)))
652
653// --- Parsers for clauses --------------------------------------------
654
655/// `MOBClause` is a clause that has a
656/// std::tuple<Modifiers, OmpObjectList, bool>.
657/// Helper function to create a typical modifiers-objects clause, where the
658/// commas separating individual modifiers are optional, and the clause
659/// contains a bool member to indicate whether it was fully comma-separated
660/// or not.
661template <bool CommaSeparated, typename MOBClause>
662static inline MOBClause makeMobClause(
663 std::list<typename MOBClause::Modifier> &&mods, OmpObjectList &&objs) {
664 if (!mods.empty()) {
665 return MOBClause{std::move(mods), std::move(objs), CommaSeparated};
666 } else {
667 using ListTy = std::list<typename MOBClause::Modifier>;
668 return MOBClause{std::optional<ListTy>{}, std::move(objs), CommaSeparated};
669 }
670}
671
672TYPE_PARSER(construct<OmpAdjustArgsClause>(
673 (Parser<OmpAdjustArgsClause::OmpAdjustOp>{} / ":"),
674 Parser<OmpObjectList>{}))
675
676// [5.0] 2.10.1 affinity([aff-modifier:] locator-list)
677// aff-modifier: interator-modifier
678TYPE_PARSER(construct<OmpAffinityClause>(
679 maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),
680 Parser<OmpObjectList>{}))
681
682// 2.4 Requires construct [OpenMP 5.0]
683// atomic-default-mem-order-clause ->
684// acq_rel
685// acquire
686// relaxed
687// release
688// seq_cst
689TYPE_PARSER(construct<OmpAtomicDefaultMemOrderClause>(
690 "ACQ_REL" >> pure(common::OmpMemoryOrderType::Acq_Rel) ||
691 "ACQUIRE" >> pure(common::OmpMemoryOrderType::Acquire) ||
692 "RELAXED" >> pure(common::OmpMemoryOrderType::Relaxed) ||
693 "RELEASE" >> pure(common::OmpMemoryOrderType::Release) ||
694 "SEQ_CST" >> pure(common::OmpMemoryOrderType::Seq_Cst)))
695
696TYPE_PARSER(construct<OmpCancellationConstructTypeClause>(
697 OmpDirectiveNameParser{}, maybe(parenthesized(scalarLogicalExpr))))
698
699TYPE_PARSER(construct<OmpAppendArgsClause>(
700 nonemptyList(Parser<OmpAppendArgsClause::OmpAppendOp>{})))
701
702// 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
703TYPE_PARSER(construct<OmpDefaultClause::DataSharingAttribute>(
704 "PRIVATE" >> pure(OmpDefaultClause::DataSharingAttribute::Private) ||
705 "FIRSTPRIVATE" >>
706 pure(OmpDefaultClause::DataSharingAttribute::Firstprivate) ||
707 "SHARED" >> pure(OmpDefaultClause::DataSharingAttribute::Shared) ||
708 "NONE" >> pure(OmpDefaultClause::DataSharingAttribute::None)))
709
710TYPE_PARSER(construct<OmpDefaultClause>(
711 construct<OmpDefaultClause>(
712 Parser<OmpDefaultClause::DataSharingAttribute>{}) ||
713 construct<OmpDefaultClause>(indirect(Parser<OmpDirectiveSpecification>{}))))
714
715TYPE_PARSER(construct<OmpFailClause>(
716 "ACQ_REL" >> pure(common::OmpMemoryOrderType::Acq_Rel) ||
717 "ACQUIRE" >> pure(common::OmpMemoryOrderType::Acquire) ||
718 "RELAXED" >> pure(common::OmpMemoryOrderType::Relaxed) ||
719 "RELEASE" >> pure(common::OmpMemoryOrderType::Release) ||
720 "SEQ_CST" >> pure(common::OmpMemoryOrderType::Seq_Cst)))
721
722// 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD)
723TYPE_PARSER(construct<OmpProcBindClause>(
724 "CLOSE" >> pure(OmpProcBindClause::AffinityPolicy::Close) ||
725 "MASTER" >> pure(OmpProcBindClause::AffinityPolicy::Master) ||
726 "PRIMARY" >> pure(OmpProcBindClause::AffinityPolicy::Primary) ||
727 "SPREAD" >> pure(OmpProcBindClause::AffinityPolicy::Spread)))
728
729TYPE_PARSER(construct<OmpMapClause>(
730 applyFunction<OmpMapClause>(makeMobClause<true>,
731 modifierList<OmpMapClause>(","_tok), Parser<OmpObjectList>{}) ||
732 applyFunction<OmpMapClause>(makeMobClause<false>,
733 modifierList<OmpMapClause>(maybe(","_tok)), Parser<OmpObjectList>{})))
734
735// [OpenMP 5.0]
736// 2.19.7.2 defaultmap(implicit-behavior[:variable-category])
737// implicit-behavior -> ALLOC | TO | FROM | TOFROM | FIRSRTPRIVATE | NONE |
738// DEFAULT | PRESENT
739// variable-category -> ALL | SCALAR | AGGREGATE | ALLOCATABLE | POINTER
740TYPE_PARSER(construct<OmpDefaultmapClause>(
741 construct<OmpDefaultmapClause::ImplicitBehavior>(
742 "ALLOC" >> pure(OmpDefaultmapClause::ImplicitBehavior::Alloc) ||
743 "TO"_id >> pure(OmpDefaultmapClause::ImplicitBehavior::To) ||
744 "FROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::From) ||
745 "TOFROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::Tofrom) ||
746 "FIRSTPRIVATE" >>
747 pure(OmpDefaultmapClause::ImplicitBehavior::Firstprivate) ||
748 "NONE" >> pure(OmpDefaultmapClause::ImplicitBehavior::None) ||
749 "DEFAULT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Default) ||
750 "PRESENT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Present)),
751 maybe(":" >> nonemptyList(Parser<OmpDefaultmapClause::Modifier>{}))))
752
753TYPE_PARSER(construct<OmpScheduleClause::Kind>(
754 "STATIC" >> pure(OmpScheduleClause::Kind::Static) ||
755 "DYNAMIC" >> pure(OmpScheduleClause::Kind::Dynamic) ||
756 "GUIDED" >> pure(OmpScheduleClause::Kind::Guided) ||
757 "AUTO" >> pure(OmpScheduleClause::Kind::Auto) ||
758 "RUNTIME" >> pure(OmpScheduleClause::Kind::Runtime)))
759
760TYPE_PARSER(construct<OmpScheduleClause>(
761 maybe(nonemptyList(Parser<OmpScheduleClause::Modifier>{}) / ":"),
762 Parser<OmpScheduleClause::Kind>{}, maybe("," >> scalarIntExpr)))
763
764// device([ device-modifier :] scalar-integer-expression)
765TYPE_PARSER(construct<OmpDeviceClause>(
766 maybe(nonemptyList(Parser<OmpDeviceClause::Modifier>{}) / ":"),
767 scalarIntExpr))
768
769// device_type(any | host | nohost)
770TYPE_PARSER(construct<OmpDeviceTypeClause>(
771 "ANY" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Any) ||
772 "HOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Host) ||
773 "NOHOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Nohost)))
774
775// 2.12 IF (directive-name-modifier: scalar-logical-expr)
776TYPE_PARSER(construct<OmpIfClause>(
777 maybe(nonemptyList(Parser<OmpIfClause::Modifier>{}) / ":"),
778 scalarLogicalExpr))
779
780TYPE_PARSER(construct<OmpReductionClause>(
781 maybe(nonemptyList(Parser<OmpReductionClause::Modifier>{}) / ":"),
782 Parser<OmpObjectList>{}))
783
784// OMP 5.0 2.19.5.6 IN_REDUCTION (reduction-identifier: variable-name-list)
785TYPE_PARSER(construct<OmpInReductionClause>(
786 maybe(nonemptyList(Parser<OmpInReductionClause::Modifier>{}) / ":"),
787 Parser<OmpObjectList>{}))
788
789TYPE_PARSER(construct<OmpTaskReductionClause>(
790 maybe(nonemptyList(Parser<OmpTaskReductionClause::Modifier>{}) / ":"),
791 Parser<OmpObjectList>{}))
792
793// OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list)
794// OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier
795// [, allocate-modifier] :]
796// variable-name-list)
797// allocate-modifier -> allocator | align
798TYPE_PARSER(construct<OmpAllocateClause>(
799 maybe(nonemptyList(Parser<OmpAllocateClause::Modifier>{}) / ":"),
800 Parser<OmpObjectList>{}))
801
802// iteration-offset -> +/- non-negative-constant-expr
803TYPE_PARSER(construct<OmpIterationOffset>(
804 Parser<DefinedOperator>{}, scalarIntConstantExpr))
805
806// iteration -> iteration-variable [+/- nonnegative-scalar-integer-constant]
807TYPE_PARSER(construct<OmpIteration>(name, maybe(Parser<OmpIterationOffset>{})))
808
809TYPE_PARSER(construct<OmpIterationVector>(nonemptyList(Parser<OmpIteration>{})))
810
811TYPE_PARSER(construct<OmpDoacross>(
812 construct<OmpDoacross>(construct<OmpDoacross::Sink>(
813 "SINK"_tok >> ":"_tok >> Parser<OmpIterationVector>{})) ||
814 construct<OmpDoacross>(construct<OmpDoacross::Source>("SOURCE"_tok))))
815
816TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
817 construct<OmpDependClause>(
818 // Try to parse OmpDoacross first, because TaskDep will succeed on
819 // "sink: xxx", interpreting it to not have any modifiers, and "sink"
820 // being an OmpObject. Parsing of the TaskDep variant will stop right
821 // after the "sink", leaving the ": xxx" unvisited.
822 construct<OmpDependClause>(Parser<OmpDoacross>{}) ||
823 // Parse TaskDep after Doacross.
824 construct<OmpDependClause>(construct<OmpDependClause::TaskDep>(
825 maybe(nonemptyList(Parser<OmpDependClause::TaskDep::Modifier>{}) /
826 ": "),
827 Parser<OmpObjectList>{}))))
828
829TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US,
830 construct<OmpDoacrossClause>(Parser<OmpDoacross>{}))
831
832TYPE_PARSER(construct<OmpFromClause>(
833 applyFunction<OmpFromClause>(makeMobClause<true>,
834 modifierList<OmpFromClause>(","_tok), Parser<OmpObjectList>{}) ||
835 applyFunction<OmpFromClause>(makeMobClause<false>,
836 modifierList<OmpFromClause>(maybe(","_tok)), Parser<OmpObjectList>{})))
837
838TYPE_PARSER(construct<OmpToClause>(
839 applyFunction<OmpToClause>(makeMobClause<true>,
840 modifierList<OmpToClause>(","_tok), Parser<OmpObjectList>{}) ||
841 applyFunction<OmpToClause>(makeMobClause<false>,
842 modifierList<OmpToClause>(maybe(","_tok)), Parser<OmpObjectList>{})))
843
844OmpLinearClause makeLinearFromOldSyntax(OmpLinearClause::Modifier &&lm,
845 OmpObjectList &&objs, std::optional<OmpLinearClause::Modifier> &&ssm) {
846 std::list<OmpLinearClause::Modifier> mods;
847 mods.emplace_back(std::move(lm));
848 if (ssm) {
849 mods.emplace_back(std::move(*ssm));
850 }
851 return OmpLinearClause{std::move(objs),
852 mods.empty() ? decltype(mods){} : std::move(mods),
853 /*PostModified=*/false};
854}
855
856TYPE_PARSER(
857 // Parse the "modifier(x)" first, because syntacticaly it will match
858 // an array element (i.e. a list item).
859 // LINEAR(linear-modifier(list) [: step-simple-modifier])
860 construct<OmpLinearClause>( //
861 applyFunction<OmpLinearClause>(makeLinearFromOldSyntax,
862 SpecificModifierParser<OmpLinearModifier, OmpLinearClause>{},
863 parenthesized(Parser<OmpObjectList>{}),
864 maybe(":"_tok >> SpecificModifierParser<OmpStepSimpleModifier,
865 OmpLinearClause>{}))) ||
866 // LINEAR(list [: modifiers])
867 construct<OmpLinearClause>( //
868 Parser<OmpObjectList>{},
869 maybe(":"_tok >> nonemptyList(Parser<OmpLinearClause::Modifier>{})),
870 /*PostModified=*/pure(true)))
871
872// OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle)
873TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{}))
874
875TYPE_PARSER(construct<OmpHintClause>(scalarIntConstantExpr))
876
877// init clause
878TYPE_PARSER(construct<OmpInitClause>(
879 maybe(nonemptyList(Parser<OmpInitClause::Modifier>{}) / ":"),
880 Parser<OmpObject>{}))
881
882// 2.8.1 ALIGNED (list: alignment)
883TYPE_PARSER(construct<OmpAlignedClause>(Parser<OmpObjectList>{},
884 maybe(":" >> nonemptyList(Parser<OmpAlignedClause::Modifier>{}))))
885
886TYPE_PARSER( //
887 construct<OmpUpdateClause>(parenthesized(Parser<OmpDependenceType>{})) ||
888 construct<OmpUpdateClause>(parenthesized(Parser<OmpTaskDependenceType>{})))
889
890TYPE_PARSER(construct<OmpOrderClause>(
891 maybe(nonemptyList(Parser<OmpOrderClause::Modifier>{}) / ":"),
892 "CONCURRENT" >> pure(OmpOrderClause::Ordering::Concurrent)))
893
894TYPE_PARSER(construct<OmpMatchClause>(
895 Parser<traits::OmpContextSelectorSpecification>{}))
896
897TYPE_PARSER(construct<OmpOtherwiseClause>(
898 maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
899
900TYPE_PARSER(construct<OmpWhenClause>(
901 maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
902 maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
903
904// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
905TYPE_PARSER(construct<OmpGrainsizeClause>(
906 maybe(nonemptyList(Parser<OmpGrainsizeClause::Modifier>{}) / ":"),
907 scalarIntExpr))
908
909// OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression)
910TYPE_PARSER(construct<OmpNumTasksClause>(
911 maybe(nonemptyList(Parser<OmpNumTasksClause::Modifier>{}) / ":"),
912 scalarIntExpr))
913
914TYPE_PARSER(
915 construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/"))
916
917// OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list)
918TYPE_PARSER(construct<OmpLastprivateClause>(
919 maybe(nonemptyList(Parser<OmpLastprivateClause::Modifier>{}) / ":"),
920 Parser<OmpObjectList>{}))
921
922// OMP 5.2 11.7.1 BIND ( PARALLEL | TEAMS | THREAD )
923TYPE_PARSER(construct<OmpBindClause>(
924 "PARALLEL" >> pure(OmpBindClause::Binding::Parallel) ||
925 "TEAMS" >> pure(OmpBindClause::Binding::Teams) ||
926 "THREAD" >> pure(OmpBindClause::Binding::Thread)))
927
928TYPE_PARSER(construct<OmpAlignClause>(scalarIntExpr))
929
930TYPE_PARSER(construct<OmpAtClause>(
931 "EXECUTION" >> pure(OmpAtClause::ActionTime::Execution) ||
932 "COMPILATION" >> pure(OmpAtClause::ActionTime::Compilation)))
933
934TYPE_PARSER(construct<OmpSeverityClause>(
935 "FATAL" >> pure(OmpSeverityClause::Severity::Fatal) ||
936 "WARNING" >> pure(OmpSeverityClause::Severity::Warning)))
937
938TYPE_PARSER(construct<OmpMessageClause>(expr))
939
940TYPE_PARSER(construct<OmpHoldsClause>(indirect(expr)))
941TYPE_PARSER(construct<OmpAbsentClause>(many(maybe(","_tok) >>
942 construct<llvm::omp::Directive>(unwrap(OmpDirectiveNameParser{})))))
943TYPE_PARSER(construct<OmpContainsClause>(many(maybe(","_tok) >>
944 construct<llvm::omp::Directive>(unwrap(OmpDirectiveNameParser{})))))
945
946TYPE_PARSER( //
947 "ABSENT" >> construct<OmpClause>(construct<OmpClause::Absent>(
948 parenthesized(Parser<OmpAbsentClause>{}))) ||
949 "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
950 "ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
951 "ADJUST_ARGS" >> construct<OmpClause>(construct<OmpClause::AdjustArgs>(
952 parenthesized(Parser<OmpAdjustArgsClause>{}))) ||
953 "AFFINITY" >> construct<OmpClause>(construct<OmpClause::Affinity>(
954 parenthesized(Parser<OmpAffinityClause>{}))) ||
955 "ALIGN" >> construct<OmpClause>(construct<OmpClause::Align>(
956 parenthesized(Parser<OmpAlignClause>{}))) ||
957 "ALIGNED" >> construct<OmpClause>(construct<OmpClause::Aligned>(
958 parenthesized(Parser<OmpAlignedClause>{}))) ||
959 "ALLOCATE" >> construct<OmpClause>(construct<OmpClause::Allocate>(
960 parenthesized(Parser<OmpAllocateClause>{}))) ||
961 "APPEND_ARGS" >> construct<OmpClause>(construct<OmpClause::AppendArgs>(
962 parenthesized(Parser<OmpAppendArgsClause>{}))) ||
963 "ALLOCATOR" >> construct<OmpClause>(construct<OmpClause::Allocator>(
964 parenthesized(scalarIntExpr))) ||
965 "AT" >> construct<OmpClause>(construct<OmpClause::At>(
966 parenthesized(Parser<OmpAtClause>{}))) ||
967 "ATOMIC_DEFAULT_MEM_ORDER" >>
968 construct<OmpClause>(construct<OmpClause::AtomicDefaultMemOrder>(
969 parenthesized(Parser<OmpAtomicDefaultMemOrderClause>{}))) ||
970 "BIND" >> construct<OmpClause>(construct<OmpClause::Bind>(
971 parenthesized(Parser<OmpBindClause>{}))) ||
972 "CAPTURE" >> construct<OmpClause>(construct<OmpClause::Capture>()) ||
973 "COLLAPSE" >> construct<OmpClause>(construct<OmpClause::Collapse>(
974 parenthesized(scalarIntConstantExpr))) ||
975 "COMPARE" >> construct<OmpClause>(construct<OmpClause::Compare>()) ||
976 "CONTAINS" >> construct<OmpClause>(construct<OmpClause::Contains>(
977 parenthesized(Parser<OmpContainsClause>{}))) ||
978 "COPYIN" >> construct<OmpClause>(construct<OmpClause::Copyin>(
979 parenthesized(Parser<OmpObjectList>{}))) ||
980 "COPYPRIVATE" >> construct<OmpClause>(construct<OmpClause::Copyprivate>(
981 (parenthesized(Parser<OmpObjectList>{})))) ||
982 "DEFAULT"_id >> construct<OmpClause>(construct<OmpClause::Default>(
983 parenthesized(Parser<OmpDefaultClause>{}))) ||
984 "DEFAULTMAP" >> construct<OmpClause>(construct<OmpClause::Defaultmap>(
985 parenthesized(Parser<OmpDefaultmapClause>{}))) ||
986 "DEPEND" >> construct<OmpClause>(construct<OmpClause::Depend>(
987 parenthesized(Parser<OmpDependClause>{}))) ||
988 "DESTROY" >>
989 construct<OmpClause>(construct<OmpClause::Destroy>(maybe(parenthesized(
990 construct<OmpDestroyClause>(Parser<OmpObject>{}))))) ||
991 "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
992 parenthesized(Parser<OmpDeviceClause>{}))) ||
993 "DEVICE_TYPE" >> construct<OmpClause>(construct<OmpClause::DeviceType>(
994 parenthesized(Parser<OmpDeviceTypeClause>{}))) ||
995 "DIST_SCHEDULE" >>
996 construct<OmpClause>(construct<OmpClause::DistSchedule>(
997 parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||
998 "DOACROSS" >>
999 construct<OmpClause>(parenthesized(Parser<OmpDoacrossClause>{})) ||
1000 "DYNAMIC_ALLOCATORS" >>
1001 construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) ||
1002 "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>(
1003 parenthesized(Parser<OmpObjectList>{}))) ||
1004 "EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>(
1005 parenthesized(Parser<OmpObjectList>{}))) ||
1006 "FAIL" >> construct<OmpClause>(construct<OmpClause::Fail>(
1007 parenthesized(Parser<OmpFailClause>{}))) ||
1008 "FILTER" >> construct<OmpClause>(construct<OmpClause::Filter>(
1009 parenthesized(scalarIntExpr))) ||
1010 "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
1011 parenthesized(scalarLogicalExpr))) ||
1012 "FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
1013 parenthesized(Parser<OmpObjectList>{}))) ||
1014 "FROM" >> construct<OmpClause>(construct<OmpClause::From>(
1015 parenthesized(Parser<OmpFromClause>{}))) ||
1016 "FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
1017 "GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
1018 parenthesized(Parser<OmpGrainsizeClause>{}))) ||
1019 "HAS_DEVICE_ADDR" >>
1020 construct<OmpClause>(construct<OmpClause::HasDeviceAddr>(
1021 parenthesized(Parser<OmpObjectList>{}))) ||
1022 "HINT" >> construct<OmpClause>(construct<OmpClause::Hint>(
1023 parenthesized(Parser<OmpHintClause>{}))) ||
1024 "HOLDS" >> construct<OmpClause>(construct<OmpClause::Holds>(
1025 parenthesized(Parser<OmpHoldsClause>{}))) ||
1026 "IF" >> construct<OmpClause>(construct<OmpClause::If>(
1027 parenthesized(Parser<OmpIfClause>{}))) ||
1028 "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
1029 "INDIRECT" >> construct<OmpClause>(construct<OmpClause::Indirect>(
1030 maybe(parenthesized(scalarLogicalExpr)))) ||
1031 "INIT" >> construct<OmpClause>(construct<OmpClause::Init>(
1032 parenthesized(Parser<OmpInitClause>{}))) ||
1033 "INCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Inclusive>(
1034 parenthesized(Parser<OmpObjectList>{}))) ||
1035 "INITIALIZER" >> construct<OmpClause>(construct<OmpClause::Initializer>(
1036 parenthesized(Parser<OmpInitializerClause>{}))) ||
1037 "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
1038 parenthesized(Parser<OmpObjectList>{}))) ||
1039 "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
1040 parenthesized(Parser<OmpLastprivateClause>{}))) ||
1041 "LINEAR" >> construct<OmpClause>(construct<OmpClause::Linear>(
1042 parenthesized(Parser<OmpLinearClause>{}))) ||
1043 "LINK" >> construct<OmpClause>(construct<OmpClause::Link>(
1044 parenthesized(Parser<OmpObjectList>{}))) ||
1045 "MAP" >> construct<OmpClause>(construct<OmpClause::Map>(
1046 parenthesized(Parser<OmpMapClause>{}))) ||
1047 "MATCH" >> construct<OmpClause>(construct<OmpClause::Match>(
1048 parenthesized(Parser<OmpMatchClause>{}))) ||
1049 "MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) ||
1050 "MESSAGE" >> construct<OmpClause>(construct<OmpClause::Message>(
1051 parenthesized(Parser<OmpMessageClause>{}))) ||
1052 "NOCONTEXT" >> construct<OmpClause>(construct<OmpClause::Nocontext>(
1053 parenthesized(scalarLogicalExpr))) ||
1054 "NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) ||
1055 "NONTEMPORAL" >> construct<OmpClause>(construct<OmpClause::Nontemporal>(
1056 parenthesized(nonemptyList(name)))) ||
1057 "NOTINBRANCH" >>
1058 construct<OmpClause>(construct<OmpClause::Notinbranch>()) ||
1059 "NOVARIANTS" >> construct<OmpClause>(construct<OmpClause::Novariants>(
1060 parenthesized(scalarLogicalExpr))) ||
1061 "NOWAIT" >> construct<OmpClause>(construct<OmpClause::Nowait>()) ||
1062 "NO_OPENMP"_id >> construct<OmpClause>(construct<OmpClause::NoOpenmp>()) ||
1063 "NO_OPENMP_ROUTINES" >>
1064 construct<OmpClause>(construct<OmpClause::NoOpenmpRoutines>()) ||
1065 "NO_PARALLELISM" >>
1066 construct<OmpClause>(construct<OmpClause::NoParallelism>()) ||
1067 "NUM_TASKS" >> construct<OmpClause>(construct<OmpClause::NumTasks>(
1068 parenthesized(Parser<OmpNumTasksClause>{}))) ||
1069 "NUM_TEAMS" >> construct<OmpClause>(construct<OmpClause::NumTeams>(
1070 parenthesized(scalarIntExpr))) ||
1071 "NUM_THREADS" >> construct<OmpClause>(construct<OmpClause::NumThreads>(
1072 parenthesized(scalarIntExpr))) ||
1073 "OMPX_BARE" >> construct<OmpClause>(construct<OmpClause::OmpxBare>()) ||
1074 "ORDER" >> construct<OmpClause>(construct<OmpClause::Order>(
1075 parenthesized(Parser<OmpOrderClause>{}))) ||
1076 "ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>(
1077 maybe(parenthesized(scalarIntConstantExpr)))) ||
1078 "OTHERWISE" >> construct<OmpClause>(construct<OmpClause::Otherwise>(
1079 maybe(parenthesized(Parser<OmpOtherwiseClause>{})))) ||
1080 "PARTIAL" >> construct<OmpClause>(construct<OmpClause::Partial>(
1081 maybe(parenthesized(scalarIntConstantExpr)))) ||
1082 "PRIORITY" >> construct<OmpClause>(construct<OmpClause::Priority>(
1083 parenthesized(scalarIntExpr))) ||
1084 "PRIVATE" >> construct<OmpClause>(construct<OmpClause::Private>(
1085 parenthesized(Parser<OmpObjectList>{}))) ||
1086 "PROC_BIND" >> construct<OmpClause>(construct<OmpClause::ProcBind>(
1087 parenthesized(Parser<OmpProcBindClause>{}))) ||
1088 "REDUCTION"_id >> construct<OmpClause>(construct<OmpClause::Reduction>(
1089 parenthesized(Parser<OmpReductionClause>{}))) ||
1090 "IN_REDUCTION" >> construct<OmpClause>(construct<OmpClause::InReduction>(
1091 parenthesized(Parser<OmpInReductionClause>{}))) ||
1092 "DETACH" >> construct<OmpClause>(construct<OmpClause::Detach>(
1093 parenthesized(Parser<OmpDetachClause>{}))) ||
1094 "TASK_REDUCTION" >>
1095 construct<OmpClause>(construct<OmpClause::TaskReduction>(
1096 parenthesized(Parser<OmpTaskReductionClause>{}))) ||
1097 "READ" >> construct<OmpClause>(construct<OmpClause::Read>()) ||
1098 "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()) ||
1099 "RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
1100 "REVERSE_OFFLOAD" >>
1101 construct<OmpClause>(construct<OmpClause::ReverseOffload>()) ||
1102 "SAFELEN" >> construct<OmpClause>(construct<OmpClause::Safelen>(
1103 parenthesized(scalarIntConstantExpr))) ||
1104 "SCHEDULE" >> construct<OmpClause>(construct<OmpClause::Schedule>(
1105 parenthesized(Parser<OmpScheduleClause>{}))) ||
1106 "SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) ||
1107 "SEVERITY" >> construct<OmpClause>(construct<OmpClause::Severity>(
1108 parenthesized(Parser<OmpSeverityClause>{}))) ||
1109 "SHARED" >> construct<OmpClause>(construct<OmpClause::Shared>(
1110 parenthesized(Parser<OmpObjectList>{}))) ||
1111 "SIMD"_id >> construct<OmpClause>(construct<OmpClause::Simd>()) ||
1112 "SIMDLEN" >> construct<OmpClause>(construct<OmpClause::Simdlen>(
1113 parenthesized(scalarIntConstantExpr))) ||
1114 "SIZES" >> construct<OmpClause>(construct<OmpClause::Sizes>(
1115 parenthesized(nonemptyList(scalarIntExpr)))) ||
1116 "PERMUTATION" >> construct<OmpClause>(construct<OmpClause::Permutation>(
1117 parenthesized(nonemptyList(scalarIntExpr)))) ||
1118 "THREADS" >> construct<OmpClause>(construct<OmpClause::Threads>()) ||
1119 "THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
1120 parenthesized(scalarIntExpr))) ||
1121 "TO" >> construct<OmpClause>(construct<OmpClause::To>(
1122 parenthesized(Parser<OmpToClause>{}))) ||
1123 "USE" >> construct<OmpClause>(construct<OmpClause::Use>(
1124 parenthesized(Parser<OmpObject>{}))) ||
1125 "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
1126 parenthesized(Parser<OmpObjectList>{}))) ||
1127 "USE_DEVICE_ADDR" >>
1128 construct<OmpClause>(construct<OmpClause::UseDeviceAddr>(
1129 parenthesized(Parser<OmpObjectList>{}))) ||
1130 "UNIFIED_ADDRESS" >>
1131 construct<OmpClause>(construct<OmpClause::UnifiedAddress>()) ||
1132 "UNIFIED_SHARED_MEMORY" >>
1133 construct<OmpClause>(construct<OmpClause::UnifiedSharedMemory>()) ||
1134 "UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>(
1135 parenthesized(nonemptyList(name)))) ||
1136 "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()) ||
1137 "UPDATE" >> construct<OmpClause>(construct<OmpClause::Update>(
1138 maybe(Parser<OmpUpdateClause>{}))) ||
1139 "WHEN" >> construct<OmpClause>(construct<OmpClause::When>(
1140 parenthesized(Parser<OmpWhenClause>{}))) ||
1141 "WRITE" >> construct<OmpClause>(construct<OmpClause::Write>()) ||
1142 // Cancellable constructs
1143 construct<OmpClause>(construct<OmpClause::CancellationConstructType>(
1144 Parser<OmpCancellationConstructTypeClause>{})))
1145
1146// [Clause, [Clause], ...]
1147TYPE_PARSER(sourced(construct<OmpClauseList>(
1148 many(maybe(","_tok) >> sourced(Parser<OmpClause>{})))))
1149
1150// 2.1 (variable | /common-block/ | array-sections)
1151TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{})))
1152
1153TYPE_PARSER(sourced(construct<OmpErrorDirective>(
1154 verbatim("ERROR"_tok), Parser<OmpClauseList>{})))
1155
1156// --- Parsers for directives and constructs --------------------------
1157
1158TYPE_PARSER(sourced(construct<OmpDirectiveName>(OmpDirectiveNameParser{})))
1159
1160OmpDirectiveSpecification static makeFlushFromOldSyntax(Verbatim &&text,
1161 std::optional<OmpClauseList> &&clauses,
1162 std::optional<OmpArgumentList> &&args,
1163 OmpDirectiveSpecification::Flags &&flags) {
1164 return OmpDirectiveSpecification{OmpDirectiveName(text), std::move(args),
1165 std::move(clauses), std::move(flags)};
1166}
1167
1168TYPE_PARSER(sourced(
1169 // Parse the old syntax: FLUSH [clauses] [(objects)]
1170 construct<OmpDirectiveSpecification>(
1171 // Force this old-syntax parser to fail for FLUSH followed by '('.
1172 // Otherwise it could succeed on the new syntax but have one of
1173 // lists absent in the parsed result.
1174 // E.g. for FLUSH(x) SEQ_CST it would find no clauses following
1175 // the directive name, parse the argument list "(x)" and stop.
1176 applyFunction<OmpDirectiveSpecification>(makeFlushFromOldSyntax,
1177 verbatim("FLUSH"_tok) / !lookAhead("("_tok),
1178 maybe(Parser<OmpClauseList>{}),
1179 maybe(parenthesized(Parser<OmpArgumentList>{})),
1180 pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax))) ||
1181 // Parse the standard syntax: directive [(arguments)] [clauses]
1182 construct<OmpDirectiveSpecification>( //
1183 sourced(OmpDirectiveNameParser{}),
1184 maybe(parenthesized(Parser<OmpArgumentList>{})),
1185 maybe(Parser<OmpClauseList>{}),
1186 pure(OmpDirectiveSpecification::Flags::None))))
1187
1188TYPE_PARSER(sourced(construct<OmpNothingDirective>("NOTHING" >> ok)))
1189
1190TYPE_PARSER(sourced(construct<OpenMPUtilityConstruct>(
1191 sourced(construct<OpenMPUtilityConstruct>(
1192 sourced(Parser<OmpErrorDirective>{}))) ||
1193 sourced(construct<OpenMPUtilityConstruct>(
1194 sourced(Parser<OmpNothingDirective>{}))))))
1195
1196TYPE_PARSER(sourced(construct<OmpMetadirectiveDirective>(
1197 verbatim("METADIRECTIVE"_tok), Parser<OmpClauseList>{})))
1198
1199// Omp directives enclosing do loop
1200TYPE_PARSER(sourced(construct<OmpLoopDirective>(first(
1201 "DISTRIBUTE PARALLEL DO SIMD" >>
1202 pure(llvm::omp::Directive::OMPD_distribute_parallel_do_simd),
1203 "DISTRIBUTE PARALLEL DO" >>
1204 pure(llvm::omp::Directive::OMPD_distribute_parallel_do),
1205 "DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_distribute_simd),
1206 "DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_distribute),
1207 "DO SIMD" >> pure(llvm::omp::Directive::OMPD_do_simd),
1208 "DO" >> pure(llvm::omp::Directive::OMPD_do),
1209 "LOOP" >> pure(llvm::omp::Directive::OMPD_loop),
1210 "MASKED TASKLOOP SIMD" >>
1211 pure(llvm::omp::Directive::OMPD_masked_taskloop_simd),
1212 "MASKED TASKLOOP" >> pure(llvm::omp::Directive::OMPD_masked_taskloop),
1213 "MASTER TASKLOOP SIMD" >>
1214 pure(llvm::omp::Directive::OMPD_master_taskloop_simd),
1215 "MASTER TASKLOOP" >> pure(llvm::omp::Directive::OMPD_master_taskloop),
1216 "PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_do_simd),
1217 "PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_parallel_do),
1218 "PARALLEL MASKED TASKLOOP SIMD" >>
1219 pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop_simd),
1220 "PARALLEL MASKED TASKLOOP" >>
1221 pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop),
1222 "PARALLEL MASTER TASKLOOP SIMD" >>
1223 pure(llvm::omp::Directive::OMPD_parallel_master_taskloop_simd),
1224 "PARALLEL MASTER TASKLOOP" >>
1225 pure(llvm::omp::Directive::OMPD_parallel_master_taskloop),
1226 "SIMD" >> pure(llvm::omp::Directive::OMPD_simd),
1227 "TARGET LOOP" >> pure(llvm::omp::Directive::OMPD_target_loop),
1228 "TARGET PARALLEL DO SIMD" >>
1229 pure(llvm::omp::Directive::OMPD_target_parallel_do_simd),
1230 "TARGET PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_target_parallel_do),
1231 "TARGET PARALLEL LOOP" >>
1232 pure(llvm::omp::Directive::OMPD_target_parallel_loop),
1233 "TARGET SIMD" >> pure(llvm::omp::Directive::OMPD_target_simd),
1234 "TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
1235 pure(llvm::omp::Directive::
1236 OMPD_target_teams_distribute_parallel_do_simd),
1237 "TARGET TEAMS DISTRIBUTE PARALLEL DO" >>
1238 pure(llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do),
1239 "TARGET TEAMS DISTRIBUTE SIMD" >>
1240 pure(llvm::omp::Directive::OMPD_target_teams_distribute_simd),
1241 "TARGET TEAMS DISTRIBUTE" >>
1242 pure(llvm::omp::Directive::OMPD_target_teams_distribute),
1243 "TARGET TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_target_teams_loop),
1244 "TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_taskloop_simd),
1245 "TASKLOOP" >> pure(llvm::omp::Directive::OMPD_taskloop),
1246 "TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
1247 pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd),
1248 "TEAMS DISTRIBUTE PARALLEL DO" >>
1249 pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do),
1250 "TEAMS DISTRIBUTE SIMD" >>
1251 pure(llvm::omp::Directive::OMPD_teams_distribute_simd),
1252 "TEAMS DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_teams_distribute),
1253 "TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_teams_loop),
1254 "TILE" >> pure(llvm::omp::Directive::OMPD_tile),
1255 "UNROLL" >> pure(llvm::omp::Directive::OMPD_unroll)))))
1256
1257TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>(
1258 sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{})))
1259
1260struct OmpEndDirectiveParser {
1261 using resultType = OmpDirectiveSpecification;
1262
1263 constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) : dir_(dir) {}
1264
1265 std::optional<resultType> Parse(ParseState &state) const {
1266 if ((startOmpLine >> "END"_sptok).Parse(state)) {
1267 auto &&dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};
1268 if (dirSpec && dirSpec->DirId() == dir_) {
1269 return std::move(dirSpec);
1270 }
1271 }
1272 return std::nullopt;
1273 }
1274
1275private:
1276 llvm::omp::Directive dir_;
1277};
1278
1279struct OmpAllocatorsConstructParser {
1280 using resultType = OpenMPAllocatorsConstruct;
1281
1282 std::optional<resultType> Parse(ParseState &state) const {
1283 auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};
1284 if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_allocators) {
1285 return std::nullopt;
1286 }
1287
1288 // This should be an allocate-stmt. That will be checked in semantics.
1289 Block block;
1290 if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) {
1291 block.emplace_back(std::move(*stmt));
1292 }
1293 // Allow empty block. Check for this in semantics.
1294
1295 auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_allocators}};
1296 return OpenMPAllocatorsConstruct{
1297 std::move(*dirSpec), std::move(block), *maybe(end).Parse(state)};
1298 }
1299};
1300
1301TYPE_PARSER(sourced( //
1302 construct<OpenMPAllocatorsConstruct>(
1303 "ALLOCATORS"_tok >= OmpAllocatorsConstructParser{})))
1304
1305struct OmpDispatchConstructParser {
1306 using resultType = OpenMPDispatchConstruct;
1307
1308 std::optional<resultType> Parse(ParseState &state) const {
1309 auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};
1310 if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_dispatch) {
1311 return std::nullopt;
1312 }
1313
1314 // This should be a function call. That will be checked in semantics.
1315 Block block;
1316 if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) {
1317 block.emplace_back(std::move(*stmt));
1318 }
1319 // Allow empty block. Check for this in semantics.
1320
1321 auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_dispatch}};
1322 return OpenMPDispatchConstruct{
1323 std::move(*dirSpec), std::move(block), *maybe(end).Parse(state)};
1324 }
1325};
1326
1327TYPE_PARSER(sourced( //
1328 construct<OpenMPDispatchConstruct>(
1329 "DISPATCH"_tok >= OmpDispatchConstructParser{})))
1330
1331// Parser for an arbitrary OpenMP ATOMIC construct.
1332//
1333// Depending on circumstances, an ATOMIC construct applies to one or more
1334// following statements. In certain cases when a single statement is
1335// expected, the end-directive is optional. The specifics depend on both
1336// the clauses used, and the form of the executable statement. To emit
1337// more meaningful messages in case of errors, the exact analysis of the
1338// structure of the construct will be delayed until semantic checks.
1339//
1340// The parser will first try the case when the end-directive is present,
1341// and will parse at most "BodyLimit" (and potentially zero) constructs
1342// while looking for the end-directive before it gives up.
1343// Then it will assume that no end-directive is present, and will try to
1344// parse a single executable construct as the body of the construct.
1345//
1346// The limit on the number of constructs is there to reduce the amount of
1347// unnecessary parsing when the end-directive is absent. It's higher than
1348// the maximum number of statements in any valid construct to accept cases
1349// when extra statements are present by mistake.
1350// A problem can occur when atomic constructs without end-directive follow
1351// each other closely, e.g.
1352// !$omp atomic write
1353// x = v
1354// !$omp atomic update
1355// x = x + 1
1356// ...
1357// The speculative parsing will become "recursive", and has the potential
1358// to take a (practically) infinite amount of time given a sufficiently
1359// large number of such constructs in a row. Since atomic constructs cannot
1360// contain other OpenMP constructs, guarding against recursive calls to the
1361// atomic construct parser solves the problem.
1362struct OmpAtomicConstructParser {
1363 using resultType = OpenMPAtomicConstruct;
1364
1365 static constexpr size_t BodyLimit{5};
1366
1367 std::optional<resultType> Parse(ParseState &state) const {
1368 if (recursing_) {
1369 return std::nullopt;
1370 }
1371 recursing_ = true;
1372
1373 auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};
1374 if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_atomic) {
1375 recursing_ = false;
1376 return std::nullopt;
1377 }
1378
1379 auto exec{Parser<ExecutionPartConstruct>{}};
1380 auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}};
1381 TailType tail;
1382
1383 if (ParseOne(exec, end, tail, state)) {
1384 if (!tail.first.empty()) {
1385 if (auto &&rest{attempt(LimitedTailParser(BodyLimit)).Parse(state)}) {
1386 for (auto &&s : rest->first) {
1387 tail.first.emplace_back(std::move(s));
1388 }
1389 assert(!tail.second);
1390 tail.second = std::move(rest->second);
1391 }
1392 }
1393 recursing_ = false;
1394 return OpenMPAtomicConstruct{
1395 std::move(*dirSpec), std::move(tail.first), std::move(tail.second)};
1396 }
1397
1398 recursing_ = false;
1399 return std::nullopt;
1400 }
1401
1402private:
1403 // Begin-directive + TailType = entire construct.
1404 using TailType = std::pair<Block, std::optional<OmpDirectiveSpecification>>;
1405
1406 // Parse either an ExecutionPartConstruct, or atomic end-directive. When
1407 // successful, record the result in the "tail" provided, otherwise fail.
1408 static std::optional<Success> ParseOne( //
1409 Parser<ExecutionPartConstruct> &exec, OmpEndDirectiveParser &end,
1410 TailType &tail, ParseState &state) {
1411 auto isRecovery{[](const ExecutionPartConstruct &e) {
1412 return std::holds_alternative<ErrorRecovery>(e.u);
1413 }};
1414 if (auto &&stmt{attempt(exec).Parse(state)}; stmt && !isRecovery(*stmt)) {
1415 tail.first.emplace_back(std::move(*stmt));
1416 } else if (auto &&dir{attempt(end).Parse(state)}) {
1417 tail.second = std::move(*dir);
1418 } else {
1419 return std::nullopt;
1420 }
1421 return Success{};
1422 }
1423
1424 struct LimitedTailParser {
1425 using resultType = TailType;
1426
1427 constexpr LimitedTailParser(size_t count) : count_(count) {}
1428
1429 std::optional<resultType> Parse(ParseState &state) const {
1430 auto exec{Parser<ExecutionPartConstruct>{}};
1431 auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}};
1432 TailType tail;
1433
1434 for (size_t i{0}; i != count_; ++i) {
1435 if (ParseOne(exec, end, tail, state)) {
1436 if (tail.second) {
1437 // Return when the end-directive was parsed.
1438 return std::move(tail);
1439 }
1440 } else {
1441 break;
1442 }
1443 }
1444 return std::nullopt;
1445 }
1446
1447 private:
1448 const size_t count_;
1449 };
1450
1451 // The recursion guard should become thread_local if parsing is ever
1452 // parallelized.
1453 static bool recursing_;
1454};
1455
1456bool OmpAtomicConstructParser::recursing_{false};
1457
1458TYPE_PARSER(sourced( //
1459 construct<OpenMPAtomicConstruct>(OmpAtomicConstructParser{})))
1460
1461// 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
1462// memory-order-clause ->
1463// acq_rel
1464// acquire
1465// relaxed
1466// release
1467// seq_cst
1468TYPE_PARSER(sourced(construct<OmpMemoryOrderClause>(
1469 sourced("ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
1470 "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
1471 "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()) ||
1472 "RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
1473 "SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>())))))
1474
1475static bool IsSimpleStandalone(const OmpDirectiveName &name) {
1476 switch (name.v) {
1477 case llvm::omp::Directive::OMPD_barrier:
1478 case llvm::omp::Directive::OMPD_ordered:
1479 case llvm::omp::Directive::OMPD_scan:
1480 case llvm::omp::Directive::OMPD_target_enter_data:
1481 case llvm::omp::Directive::OMPD_target_exit_data:
1482 case llvm::omp::Directive::OMPD_target_update:
1483 case llvm::omp::Directive::OMPD_taskwait:
1484 case llvm::omp::Directive::OMPD_taskyield:
1485 return true;
1486 default:
1487 return false;
1488 }
1489}
1490
1491TYPE_PARSER(sourced( //
1492 construct<OpenMPSimpleStandaloneConstruct>(
1493 predicated(OmpDirectiveNameParser{}, IsSimpleStandalone) >=
1494 Parser<OmpDirectiveSpecification>{})))
1495
1496static inline constexpr auto IsDirective(llvm::omp::Directive dir) {
1497 return [dir](const OmpDirectiveName &name) -> bool { return dir == name.v; };
1498}
1499
1500TYPE_PARSER(sourced( //
1501 construct<OpenMPFlushConstruct>(
1502 predicated(OmpDirectiveNameParser{},
1503 IsDirective(llvm::omp::Directive::OMPD_flush)) >=
1504 Parser<OmpDirectiveSpecification>{})))
1505
1506// 2.14.2 Cancellation Point construct
1507TYPE_PARSER(sourced( //
1508 construct<OpenMPCancellationPointConstruct>(
1509 predicated(OmpDirectiveNameParser{},
1510 IsDirective(llvm::omp::Directive::OMPD_cancellation_point)) >=
1511 Parser<OmpDirectiveSpecification>{})))
1512
1513// 2.14.1 Cancel construct
1514TYPE_PARSER(sourced( //
1515 construct<OpenMPCancelConstruct>(
1516 predicated(OmpDirectiveNameParser{},
1517 IsDirective(llvm::omp::Directive::OMPD_cancel)) >=
1518 Parser<OmpDirectiveSpecification>{})))
1519
1520TYPE_PARSER(sourced( //
1521 construct<OpenMPDepobjConstruct>(
1522 predicated(OmpDirectiveNameParser{},
1523 IsDirective(llvm::omp::Directive::OMPD_depobj)) >=
1524 Parser<OmpDirectiveSpecification>{})))
1525
1526// OMP 5.2 14.1 Interop construct
1527TYPE_PARSER(sourced( //
1528 construct<OpenMPInteropConstruct>(
1529 predicated(OmpDirectiveNameParser{},
1530 IsDirective(llvm::omp::Directive::OMPD_interop)) >=
1531 Parser<OmpDirectiveSpecification>{})))
1532
1533// Standalone Constructs
1534TYPE_PARSER(
1535 sourced( //
1536 construct<OpenMPStandaloneConstruct>(
1537 Parser<OpenMPSimpleStandaloneConstruct>{}) ||
1538 construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
1539 // Try CANCELLATION POINT before CANCEL.
1540 construct<OpenMPStandaloneConstruct>(
1541 Parser<OpenMPCancellationPointConstruct>{}) ||
1542 construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
1543 construct<OpenMPStandaloneConstruct>(
1544 Parser<OmpMetadirectiveDirective>{}) ||
1545 construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{}) ||
1546 construct<OpenMPStandaloneConstruct>(
1547 Parser<OpenMPInteropConstruct>{})) /
1548 endOfLine)
1549
1550// Directives enclosing structured-block
1551TYPE_PARSER(
1552 // In this context "TARGET UPDATE" can be parsed as a TARGET directive
1553 // followed by an UPDATE clause. This is the only combination at the
1554 // moment, exclude it explicitly.
1555 (!("TARGET UPDATE"_sptok || "TARGET_UPDATE"_sptok)) >=
1556 construct<OmpBlockDirective>(first(
1557 "MASKED" >> pure(llvm::omp::Directive::OMPD_masked),
1558 "MASTER" >> pure(llvm::omp::Directive::OMPD_master),
1559 "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
1560 "PARALLEL MASKED" >> pure(llvm::omp::Directive::OMPD_parallel_masked),
1561 "PARALLEL MASTER" >> pure(llvm::omp::Directive::OMPD_parallel_master),
1562 "PARALLEL WORKSHARE" >>
1563 pure(llvm::omp::Directive::OMPD_parallel_workshare),
1564 "PARALLEL" >> pure(llvm::omp::Directive::OMPD_parallel),
1565 "SCOPE" >> pure(llvm::omp::Directive::OMPD_scope),
1566 "SINGLE" >> pure(llvm::omp::Directive::OMPD_single),
1567 "TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data),
1568 "TARGET_DATA" >> pure(llvm::omp::Directive::OMPD_target_data),
1569 "TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel),
1570 "TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams),
1571 "TARGET" >> pure(llvm::omp::Directive::OMPD_target),
1572 "TASK"_id >> pure(llvm::omp::Directive::OMPD_task),
1573 "TASKGROUP" >> pure(llvm::omp::Directive::OMPD_taskgroup),
1574 "TEAMS" >> pure(llvm::omp::Directive::OMPD_teams),
1575 "WORKSHARE" >> pure(llvm::omp::Directive::OMPD_workshare))))
1576
1577TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>(
1578 sourced(Parser<OmpBlockDirective>{}), Parser<OmpClauseList>{})))
1579
1580TYPE_PARSER(construct<OmpInitializerProc>(Parser<ProcedureDesignator>{},
1581 parenthesized(many(maybe(","_tok) >> Parser<ActualArgSpec>{}))))
1582
1583TYPE_PARSER(construct<OmpInitializerClause>(
1584 construct<OmpInitializerClause>(assignmentStmt) ||
1585 construct<OmpInitializerClause>(Parser<OmpInitializerProc>{})))
1586
1587// OpenMP 5.2: 7.5.4 Declare Variant directive
1588TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
1589 verbatim("DECLARE VARIANT"_tok) || verbatim("DECLARE_VARIANT"_tok),
1590 "(" >> maybe(name / ":"), name / ")", Parser<OmpClauseList>{})))
1591
1592// 2.16 Declare Reduction Construct
1593TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
1594 verbatim("DECLARE REDUCTION"_tok) || verbatim("DECLARE_REDUCTION"_tok),
1595 "(" >> indirect(Parser<OmpReductionSpecifier>{}) / ")",
1596 maybe(Parser<OmpClauseList>{}))))
1597
1598// declare-target with list
1599TYPE_PARSER(sourced(construct<OmpDeclareTargetWithList>(
1600 parenthesized(Parser<OmpObjectList>{}))))
1601
1602// declare-target with clause
1603TYPE_PARSER(
1604 sourced(construct<OmpDeclareTargetWithClause>(Parser<OmpClauseList>{})))
1605
1606// declare-target-specifier
1607TYPE_PARSER(
1608 construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithList>{}) ||
1609 construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithClause>{}))
1610
1611// 2.10.6 Declare Target Construct
1612TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
1613 verbatim("DECLARE TARGET"_tok) || verbatim("DECLARE_TARGET"_tok),
1614 Parser<OmpDeclareTargetSpecifier>{})))
1615
1616static OmpMapperSpecifier ConstructOmpMapperSpecifier(
1617 std::optional<Name> &&mapperName, TypeSpec &&typeSpec, Name &&varName) {
1618 // If a name is present, parse: name ":" typeSpec "::" name
1619 // This matches the syntax: <mapper-name> : <type-spec> :: <variable-name>
1620 if (mapperName.has_value() && mapperName->ToString() != "default") {
1621 return OmpMapperSpecifier{
1622 mapperName->ToString(), std::move(typeSpec), std::move(varName)};
1623 }
1624 // If the name is missing, use the DerivedTypeSpec name to construct the
1625 // default mapper name.
1626 // This matches the syntax: <type-spec> :: <variable-name>
1627 if (DerivedTypeSpec * derived{std::get_if<DerivedTypeSpec>(&typeSpec.u)}) {
1628 return OmpMapperSpecifier{
1629 std::get<Name>(derived->t).ToString() + llvm::omp::OmpDefaultMapperName,
1630 std::move(typeSpec), std::move(varName)};
1631 }
1632 return OmpMapperSpecifier{std::string(llvm::omp::OmpDefaultMapperName),
1633 std::move(typeSpec), std::move(varName)};
1634}
1635
1636// mapper-specifier
1637TYPE_PARSER(applyFunction<OmpMapperSpecifier>(ConstructOmpMapperSpecifier,
1638 maybe(name / ":" / !":"_tok), typeSpec / "::", name))
1639
1640// OpenMP 5.2: 5.8.8 Declare Mapper Construct
1641TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>(
1642 verbatim("DECLARE MAPPER"_tok) || verbatim("DECLARE_MAPPER"_tok),
1643 parenthesized(Parser<OmpMapperSpecifier>{}), Parser<OmpClauseList>{})))
1644
1645TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) ||
1646 construct<OmpReductionCombiner>(Parser<FunctionReference>{}))
1647
1648// 2.13.2 OMP CRITICAL
1649TYPE_PARSER(startOmpLine >>
1650 sourced(construct<OmpEndCriticalDirective>(
1651 verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) /
1652 endOmpLine)
1653TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok),
1654 maybe(parenthesized(name)), Parser<OmpClauseList>{})) /
1655 endOmpLine)
1656
1657TYPE_PARSER(construct<OpenMPCriticalConstruct>(
1658 Parser<OmpCriticalDirective>{}, block, Parser<OmpEndCriticalDirective>{}))
1659
1660// 2.11.3 Executable Allocate directive
1661TYPE_PARSER(
1662 sourced(construct<OpenMPExecutableAllocate>(verbatim("ALLOCATE"_tok),
1663 maybe(parenthesized(Parser<OmpObjectList>{})), Parser<OmpClauseList>{},
1664 maybe(nonemptyList(Parser<OpenMPDeclarativeAllocate>{})) / endOmpLine,
1665 statement(allocateStmt))))
1666
1667// 2.8.2 Declare Simd construct
1668TYPE_PARSER(sourced(construct<OpenMPDeclareSimdConstruct>(
1669 verbatim("DECLARE SIMD"_tok) || verbatim("DECLARE_SIMD"_tok),
1670 maybe(parenthesized(name)), Parser<OmpClauseList>{})))
1671
1672// 2.4 Requires construct
1673TYPE_PARSER(sourced(construct<OpenMPRequiresConstruct>(
1674 verbatim("REQUIRES"_tok), Parser<OmpClauseList>{})))
1675
1676// 2.15.2 Threadprivate directive
1677TYPE_PARSER(sourced(construct<OpenMPThreadprivate>(
1678 verbatim("THREADPRIVATE"_tok), parenthesized(Parser<OmpObjectList>{}))))
1679
1680// 2.11.3 Declarative Allocate directive
1681TYPE_PARSER(
1682 sourced(construct<OpenMPDeclarativeAllocate>(verbatim("ALLOCATE"_tok),
1683 parenthesized(Parser<OmpObjectList>{}), Parser<OmpClauseList>{})) /
1684 lookAhead(endOmpLine / !statement(allocateStmt)))
1685
1686// Assumes Construct
1687TYPE_PARSER(sourced(construct<OpenMPDeclarativeAssumes>(
1688 verbatim("ASSUMES"_tok), Parser<OmpClauseList>{})))
1689
1690// Declarative constructs
1691TYPE_PARSER(
1692 startOmpLine >> withMessage("expected OpenMP construct"_err_en_US,
1693 sourced(construct<OpenMPDeclarativeConstruct>(
1694 Parser<OpenMPDeclarativeAssumes>{}) ||
1695 construct<OpenMPDeclarativeConstruct>(
1696 Parser<OpenMPDeclareReductionConstruct>{}) ||
1697 construct<OpenMPDeclarativeConstruct>(
1698 Parser<OpenMPDeclareMapperConstruct>{}) ||
1699 construct<OpenMPDeclarativeConstruct>(
1700 Parser<OpenMPDeclareSimdConstruct>{}) ||
1701 construct<OpenMPDeclarativeConstruct>(
1702 Parser<OpenMPDeclareTargetConstruct>{}) ||
1703 construct<OpenMPDeclarativeConstruct>(
1704 Parser<OmpDeclareVariantDirective>{}) ||
1705 construct<OpenMPDeclarativeConstruct>(
1706 Parser<OpenMPDeclarativeAllocate>{}) ||
1707 construct<OpenMPDeclarativeConstruct>(
1708 Parser<OpenMPRequiresConstruct>{}) ||
1709 construct<OpenMPDeclarativeConstruct>(
1710 Parser<OpenMPThreadprivate>{}) ||
1711 construct<OpenMPDeclarativeConstruct>(
1712 Parser<OpenMPUtilityConstruct>{}) ||
1713 construct<OpenMPDeclarativeConstruct>(
1714 Parser<OmpMetadirectiveDirective>{})) /
1715 endOmpLine))
1716
1717// Assume Construct
1718TYPE_PARSER(sourced(construct<OmpAssumeDirective>(
1719 verbatim("ASSUME"_tok), Parser<OmpClauseList>{})))
1720
1721TYPE_PARSER(sourced(construct<OmpEndAssumeDirective>(
1722 startOmpLine >> verbatim("END ASSUME"_tok))))
1723
1724TYPE_PARSER(sourced(
1725 construct<OpenMPAssumeConstruct>(Parser<OmpAssumeDirective>{} / endOmpLine,
1726 block, maybe(Parser<OmpEndAssumeDirective>{} / endOmpLine))))
1727
1728// Block Construct
1729TYPE_PARSER(construct<OpenMPBlockConstruct>(
1730 Parser<OmpBeginBlockDirective>{} / endOmpLine, block,
1731 Parser<OmpEndBlockDirective>{} / endOmpLine))
1732
1733// OMP SECTIONS Directive
1734TYPE_PARSER(construct<OmpSectionsDirective>(first(
1735 "SECTIONS" >> pure(llvm::omp::Directive::OMPD_sections),
1736 "PARALLEL SECTIONS" >> pure(llvm::omp::Directive::OMPD_parallel_sections))))
1737
1738// OMP BEGIN and END SECTIONS Directive
1739TYPE_PARSER(sourced(construct<OmpBeginSectionsDirective>(
1740 sourced(Parser<OmpSectionsDirective>{}), Parser<OmpClauseList>{})))
1741TYPE_PARSER(
1742 startOmpLine >> sourced(construct<OmpEndSectionsDirective>(
1743 sourced("END"_tok >> Parser<OmpSectionsDirective>{}),
1744 Parser<OmpClauseList>{})))
1745
1746// OMP SECTION-BLOCK
1747
1748TYPE_PARSER(construct<OpenMPSectionConstruct>(block))
1749
1750TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >>
1751 construct<OmpSectionBlocks>(nonemptySeparated(
1752 construct<OpenMPConstruct>(sourced(Parser<OpenMPSectionConstruct>{})),
1753 startOmpLine >> "SECTION"_tok / endOmpLine)))
1754
1755// OMP SECTIONS (OpenMP 5.0 - 2.8.1), PARALLEL SECTIONS (OpenMP 5.0 - 2.13.3)
1756TYPE_PARSER(construct<OpenMPSectionsConstruct>(
1757 Parser<OmpBeginSectionsDirective>{} / endOmpLine,
1758 Parser<OmpSectionBlocks>{}, Parser<OmpEndSectionsDirective>{} / endOmpLine))
1759
1760TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
1761 startOmpLine >>
1762 withMessage("expected OpenMP construct"_err_en_US,
1763 first(construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}),
1764 construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}),
1765 construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}),
1766 // OpenMPBlockConstruct is attempted before
1767 // OpenMPStandaloneConstruct to resolve !$OMP ORDERED
1768 construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}),
1769 construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}),
1770 construct<OpenMPConstruct>(Parser<OpenMPUtilityConstruct>{}),
1771 construct<OpenMPConstruct>(Parser<OpenMPDispatchConstruct>{}),
1772 construct<OpenMPConstruct>(Parser<OpenMPExecutableAllocate>{}),
1773 construct<OpenMPConstruct>(Parser<OpenMPAllocatorsConstruct>{}),
1774 construct<OpenMPConstruct>(Parser<OpenMPDeclarativeAllocate>{}),
1775 construct<OpenMPConstruct>(Parser<OpenMPAssumeConstruct>{}),
1776 construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}))))
1777
1778// END OMP Block directives
1779TYPE_PARSER(
1780 startOmpLine >> sourced(construct<OmpEndBlockDirective>(
1781 sourced("END"_tok >> Parser<OmpBlockDirective>{}),
1782 Parser<OmpClauseList>{})))
1783
1784// END OMP Loop directives
1785TYPE_PARSER(
1786 startOmpLine >> sourced(construct<OmpEndLoopDirective>(
1787 sourced("END"_tok >> Parser<OmpLoopDirective>{}),
1788 Parser<OmpClauseList>{})))
1789
1790TYPE_PARSER(construct<OpenMPLoopConstruct>(
1791 Parser<OmpBeginLoopDirective>{} / endOmpLine))
1792} // namespace Fortran::parser
1793

source code of flang/lib/Parser/openmp-parsers.cpp