llvm-project/flang/lib/Parser/openmp-parsers.cpp
Mats Petersson 0de2ccab7b
[flang][OpenMP]Improve support for DECLARE REDUCTION (#127088)
Part of the DECLARE REDUCTION was already supported by the parser, but
the semantics to add the reduction identifier wasn't implemented.

The semantics would not accept the name given by the reduction, so a few
lines added to support that.

Some tests were in place but not quite working, so fixed those up too.
Adding new tests for unparsing and parse-tree, as well as checking the
symbolic name being generated.

Lowering of DECLARE REDUCTION is not supported in this patch, and a test
that it hits the relevant TODO is in this patch (most of this was
already existing, but not actually testing the TODO message).
2025-02-19 10:39:43 +00:00

1389 lines
64 KiB
C++

//===-- lib/Parser/openmp-parsers.cpp -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Top-level grammar specification for OpenMP.
// See OpenMP-4.5-grammar.txt for documentation.
#include "basic-parsers.h"
#include "expr-parsers.h"
#include "misc-parsers.h"
#include "stmt-parser.h"
#include "token-parsers.h"
#include "type-parser-implementation.h"
#include "flang/Parser/parse-tree.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/OpenMP/OMP.h"
// OpenMP Directives and Clauses
namespace Fortran::parser {
constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok;
constexpr auto endOmpLine = space >> endOfLine;
/// Parse OpenMP directive name (this includes compound directives).
struct OmpDirectiveNameParser {
using resultType = llvm::omp::Directive;
using Token = TokenStringMatch<false, false>;
std::optional<resultType> Parse(ParseState &state) const {
for (const NameWithId &nid : directives()) {
if (attempt(Token(nid.first.data())).Parse(state)) {
return nid.second;
}
}
return std::nullopt;
}
private:
using NameWithId = std::pair<std::string, llvm::omp::Directive>;
llvm::iterator_range<const NameWithId *> directives() const;
void initTokens(NameWithId *) const;
};
llvm::iterator_range<const OmpDirectiveNameParser::NameWithId *>
OmpDirectiveNameParser::directives() const {
static NameWithId table[llvm::omp::Directive_enumSize];
[[maybe_unused]] static bool init = (initTokens(table), true);
return llvm::make_range(std::cbegin(table), std::cend(table));
}
void OmpDirectiveNameParser::initTokens(NameWithId *table) const {
for (size_t i{0}, e{llvm::omp::Directive_enumSize}; i != e; ++i) {
auto id{static_cast<llvm::omp::Directive>(i)};
llvm::StringRef name{llvm::omp::getOpenMPDirectiveName(id)};
table[i] = std::make_pair(name.str(), id);
}
// Sort the table with respect to the directive name length in a descending
// order. This is to make sure that longer names are tried first, before
// any potential prefix (e.g. "target update" before "target").
std::sort(table, table + llvm::omp::Directive_enumSize,
[](auto &a, auto &b) { return a.first.size() > b.first.size(); });
}
// --- Modifier helpers -----------------------------------------------
template <typename Clause, typename Separator> struct ModifierList {
constexpr ModifierList(Separator sep) : sep_(sep) {}
constexpr ModifierList(const ModifierList &) = default;
constexpr ModifierList(ModifierList &&) = default;
using resultType = std::list<typename Clause::Modifier>;
std::optional<resultType> Parse(ParseState &state) const {
auto listp{nonemptySeparated(Parser<typename Clause::Modifier>{}, sep_)};
if (auto result{attempt(listp).Parse(state)}) {
if (!attempt(":"_tok).Parse(state)) {
return std::nullopt;
}
return std::move(result);
}
return resultType{};
}
private:
const Separator sep_;
};
// Use a function to create ModifierList because functions allow "partial"
// template argument deduction: "modifierList<Clause>(sep)" would be legal,
// while "ModifierList<Clause>(sep)" would complain about a missing template
// argument "Separator".
template <typename Clause, typename Separator>
constexpr ModifierList<Clause, Separator> modifierList(Separator sep) {
return ModifierList<Clause, Separator>(sep);
}
// Parse the input as any modifier from ClauseTy, but only succeed if
// the result was the SpecificTy. It requires that SpecificTy is one
// of the alternatives in ClauseTy::Modifier.
// The reason to have this is that ClauseTy::Modifier has "source",
// while specific modifiers don't. This class allows to parse a specific
// modifier together with obtaining its location.
template <typename SpecificTy, typename ClauseTy>
struct SpecificModifierParser {
using resultType = typename ClauseTy::Modifier;
std::optional<resultType> Parse(ParseState &state) const {
if (auto result{attempt(Parser<resultType>{}).Parse(state)}) {
if (std::holds_alternative<SpecificTy>(result->u)) {
return result;
}
}
return std::nullopt;
}
};
// --- Iterator helpers -----------------------------------------------
// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not
// specified then the type of that iterator is default integer.
// [5.0:49:14] The iterator-type must be an integer type.
static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) {
std::list<EntityDecl> entities;
for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) {
EntityDecl entityDecl(
/*ObjectName=*/std::move(*iter), std::optional<ArraySpec>{},
std::optional<CoarraySpec>{}, std::optional<CharLength>{},
std::optional<Initialization>{});
entities.push_back(std::move(entityDecl));
}
return entities;
}
static TypeDeclarationStmt makeIterSpecDecl(
DeclarationTypeSpec &&spec, std::list<ObjectName> &&names) {
return TypeDeclarationStmt(
std::move(spec), std::list<AttrSpec>{}, makeEntityList(std::move(names)));
}
static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
// Assume INTEGER without kind selector.
DeclarationTypeSpec typeSpec(
IntrinsicTypeSpec{IntegerTypeSpec{std::nullopt}});
return TypeDeclarationStmt(std::move(typeSpec), std::list<AttrSpec>{},
makeEntityList(std::move(names)));
}
// --- Parsers for arguments ------------------------------------------
// At the moment these are only directive arguments. This is needed for
// parsing directive-specification.
TYPE_PARSER( //
construct<OmpLocator>(Parser<OmpObject>{}) ||
construct<OmpLocator>(Parser<FunctionReference>{}))
TYPE_PARSER(sourced( //
construct<OmpArgument>(Parser<OmpMapperSpecifier>{}) ||
construct<OmpArgument>(Parser<OmpReductionSpecifier>{}) ||
construct<OmpArgument>(Parser<OmpLocator>{})))
TYPE_PARSER(construct<OmpLocatorList>(nonemptyList(Parser<OmpLocator>{})))
TYPE_PARSER( //
construct<OmpTypeSpecifier>(Parser<DeclarationTypeSpec>{}) ||
construct<OmpTypeSpecifier>(Parser<TypeSpec>{}))
TYPE_PARSER(construct<OmpReductionSpecifier>( //
Parser<OmpReductionIdentifier>{},
":"_tok >> nonemptyList(Parser<OmpTypeSpecifier>{}),
maybe(":"_tok >> Parser<OmpReductionCombiner>{})))
// --- Parsers for context traits -------------------------------------
static std::string nameToString(Name &&name) { return name.ToString(); }
TYPE_PARSER(sourced(construct<OmpTraitPropertyName>( //
construct<OmpTraitPropertyName>(space >> charLiteralConstantWithoutKind) ||
construct<OmpTraitPropertyName>(
applyFunction(nameToString, Parser<Name>{})))))
TYPE_PARSER(sourced(construct<OmpTraitScore>( //
"SCORE"_id >> parenthesized(scalarIntExpr))))
TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension::Complex>(
Parser<OmpTraitPropertyName>{},
parenthesized(nonemptySeparated(
indirect(Parser<OmpTraitPropertyExtension>{}), ",")))))
TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension>(
construct<OmpTraitPropertyExtension>(
Parser<OmpTraitPropertyExtension::Complex>{}) ||
construct<OmpTraitPropertyExtension>(Parser<OmpTraitPropertyName>{}) ||
construct<OmpTraitPropertyExtension>(scalarExpr))))
TYPE_PARSER(construct<OmpTraitSelectorName::Value>(
"ARCH"_id >> pure(OmpTraitSelectorName::Value::Arch) ||
"ATOMIC_DEFAULT_MEM_ORDER"_id >>
pure(OmpTraitSelectorName::Value::Atomic_Default_Mem_Order) ||
"CONDITION"_id >> pure(OmpTraitSelectorName::Value::Condition) ||
"DEVICE_NUM"_id >> pure(OmpTraitSelectorName::Value::Device_Num) ||
"EXTENSION"_id >> pure(OmpTraitSelectorName::Value::Extension) ||
"ISA"_id >> pure(OmpTraitSelectorName::Value::Isa) ||
"KIND"_id >> pure(OmpTraitSelectorName::Value::Kind) ||
"REQUIRES"_id >> pure(OmpTraitSelectorName::Value::Requires) ||
"SIMD"_id >> pure(OmpTraitSelectorName::Value::Simd) ||
"UID"_id >> pure(OmpTraitSelectorName::Value::Uid) ||
"VENDOR"_id >> pure(OmpTraitSelectorName::Value::Vendor)))
TYPE_PARSER(sourced(construct<OmpTraitSelectorName>(
// Parse predefined names first (because of SIMD).
construct<OmpTraitSelectorName>(Parser<OmpTraitSelectorName::Value>{}) ||
construct<OmpTraitSelectorName>(OmpDirectiveNameParser{}) ||
// identifier-or-string for extensions
construct<OmpTraitSelectorName>(
applyFunction(nameToString, Parser<Name>{})) ||
construct<OmpTraitSelectorName>(space >> charLiteralConstantWithoutKind))))
// Parser for OmpTraitSelector::Properties
template <typename... PropParser>
static constexpr auto propertyListParser(PropParser... pp) {
// Parse the property list "(score(expr): item1...)" in three steps:
// 1. Parse the "("
// 2. Parse the optional "score(expr):"
// 3. Parse the "item1, ...)", together with the ")".
// The reason for including the ")" in the 3rd step is to force parsing
// the entire list in each of the alternative property parsers. Otherwise,
// the name parser could stop after "foo" in "(foo, bar(1))", without
// allowing the next parser to give the list a try.
using P = OmpTraitProperty;
return maybe("(" >> //
construct<OmpTraitSelector::Properties>(
maybe(Parser<OmpTraitScore>{} / ":"),
(attempt(nonemptyList(sourced(construct<P>(pp))) / ")") || ...)));
}
// Parser for OmpTraitSelector
struct TraitSelectorParser {
using resultType = OmpTraitSelector;
constexpr TraitSelectorParser(Parser<OmpTraitSelectorName> p) : np(p) {}
std::optional<resultType> Parse(ParseState &state) const {
auto name{attempt(np).Parse(state)};
if (!name.has_value()) {
return std::nullopt;
}
// Default fallback parser for lists that cannot be parser using the
// primary property parser.
auto extParser{Parser<OmpTraitPropertyExtension>{}};
if (auto *v{std::get_if<OmpTraitSelectorName::Value>(&name->u)}) {
// (*) The comments below show the sections of the OpenMP spec that
// describe given trait. The cases marked with a (*) are those where
// the spec doesn't assign any list-type to these traits, but for
// convenience they can be treated as if they were.
switch (*v) {
// name-list properties
case OmpTraitSelectorName::Value::Arch: // [6.0:319:18]
case OmpTraitSelectorName::Value::Extension: // [6.0:319:30]
case OmpTraitSelectorName::Value::Isa: // [6.0:319:15]
case OmpTraitSelectorName::Value::Kind: // [6.0:319:10]
case OmpTraitSelectorName::Value::Uid: // [6.0:319:23](*)
case OmpTraitSelectorName::Value::Vendor: { // [6.0:319:27]
auto pp{propertyListParser(Parser<OmpTraitPropertyName>{}, extParser)};
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
}
// clause-list
case OmpTraitSelectorName::Value::Atomic_Default_Mem_Order:
// [6.0:321:26-29](*)
case OmpTraitSelectorName::Value::Requires: // [6.0:319:33]
case OmpTraitSelectorName::Value::Simd: { // [6.0:318:31]
auto pp{propertyListParser(indirect(Parser<OmpClause>{}), extParser)};
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
}
// expr-list
case OmpTraitSelectorName::Value::Condition: // [6.0:321:33](*)
case OmpTraitSelectorName::Value::Device_Num: { // [6.0:321:23-24](*)
auto pp{propertyListParser(scalarExpr, extParser)};
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
}
} // switch
} else {
// The other alternatives are `llvm::omp::Directive`, and `std::string`.
// The former doesn't take any properties[1], the latter is a name of an
// extension[2].
// [1] [6.0:319:1-2]
// [2] [6.0:319:36-37]
auto pp{propertyListParser(extParser)};
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
}
llvm_unreachable("Unhandled trait name?");
}
private:
const Parser<OmpTraitSelectorName> np;
};
TYPE_PARSER(sourced(construct<OmpTraitSelector>(
sourced(TraitSelectorParser(Parser<OmpTraitSelectorName>{})))))
TYPE_PARSER(construct<OmpTraitSetSelectorName::Value>(
"CONSTRUCT"_id >> pure(OmpTraitSetSelectorName::Value::Construct) ||
"DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Device) ||
"IMPLEMENTATION"_id >>
pure(OmpTraitSetSelectorName::Value::Implementation) ||
"TARGET_DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Target_Device) ||
"USER"_id >> pure(OmpTraitSetSelectorName::Value::User)))
TYPE_PARSER(sourced(construct<OmpTraitSetSelectorName>(
Parser<OmpTraitSetSelectorName::Value>{})))
TYPE_PARSER(sourced(construct<OmpTraitSetSelector>( //
Parser<OmpTraitSetSelectorName>{},
"=" >> braced(nonemptySeparated(Parser<OmpTraitSelector>{}, ",")))))
TYPE_PARSER(sourced(construct<OmpContextSelectorSpecification>(
nonemptySeparated(Parser<OmpTraitSetSelector>{}, ","))))
// Note: OmpContextSelector is a type alias.
// --- Parsers for clause modifiers -----------------------------------
TYPE_PARSER(construct<OmpAlignment>(scalarIntExpr))
TYPE_PARSER(construct<OmpAlignModifier>( //
"ALIGN" >> parenthesized(scalarIntExpr)))
TYPE_PARSER(construct<OmpAllocatorComplexModifier>(
"ALLOCATOR" >> parenthesized(scalarIntExpr)))
TYPE_PARSER(construct<OmpAllocatorSimpleModifier>(scalarIntExpr))
TYPE_PARSER(construct<OmpChunkModifier>( //
"SIMD" >> pure(OmpChunkModifier::Value::Simd)))
TYPE_PARSER(construct<OmpDependenceType>(
"SINK" >> pure(OmpDependenceType::Value::Sink) ||
"SOURCE" >> pure(OmpDependenceType::Value::Source)))
TYPE_PARSER(construct<OmpDeviceModifier>(
"ANCESTOR" >> pure(OmpDeviceModifier::Value::Ancestor) ||
"DEVICE_NUM" >> pure(OmpDeviceModifier::Value::Device_Num)))
TYPE_PARSER(construct<OmpExpectation>( //
"PRESENT" >> pure(OmpExpectation::Value::Present)))
TYPE_PARSER(construct<OmpIteratorSpecifier>(
// Using Parser<TypeDeclarationStmt> or Parser<EntityDecl> has the problem
// that they will attempt to treat what follows the '=' as initialization.
// There are several issues with that,
// 1. integer :: i = 0:10 will be parsed as "integer :: i = 0", followed
// by triplet ":10".
// 2. integer :: j = i:10 will be flagged as an error because the
// initializer 'i' must be constant (in declarations). In an iterator
// specifier the 'j' is not an initializer and can be a variable.
(applyFunction<TypeDeclarationStmt>(makeIterSpecDecl,
Parser<DeclarationTypeSpec>{} / maybe("::"_tok),
nonemptyList(Parser<ObjectName>{}) / "="_tok) ||
applyFunction<TypeDeclarationStmt>(
makeIterSpecDecl, nonemptyList(Parser<ObjectName>{}) / "="_tok)),
subscriptTriplet))
// [5.0] 2.1.6 iterator -> iterator-specifier-list
TYPE_PARSER(construct<OmpIterator>( //
"ITERATOR" >>
parenthesized(nonemptyList(sourced(Parser<OmpIteratorSpecifier>{})))))
TYPE_PARSER(construct<OmpLastprivateModifier>(
"CONDITIONAL" >> pure(OmpLastprivateModifier::Value::Conditional)))
// 2.15.3.7 LINEAR (linear-list: linear-step)
// linear-list -> list | modifier(list)
// linear-modifier -> REF | VAL | UVAL
TYPE_PARSER(construct<OmpLinearModifier>( //
"REF" >> pure(OmpLinearModifier::Value::Ref) ||
"VAL" >> pure(OmpLinearModifier::Value::Val) ||
"UVAL" >> pure(OmpLinearModifier::Value::Uval)))
TYPE_PARSER(construct<OmpMapper>( //
"MAPPER"_tok >> parenthesized(Parser<ObjectName>{})))
// map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM
TYPE_PARSER(construct<OmpMapType>( //
"ALLOC" >> pure(OmpMapType::Value::Alloc) ||
"DELETE" >> pure(OmpMapType::Value::Delete) ||
"FROM" >> pure(OmpMapType::Value::From) ||
"RELEASE" >> pure(OmpMapType::Value::Release) ||
"TO"_id >> pure(OmpMapType::Value::To) ||
"TOFROM" >> pure(OmpMapType::Value::Tofrom)))
// map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT
TYPE_PARSER(construct<OmpMapTypeModifier>(
"ALWAYS" >> pure(OmpMapTypeModifier::Value::Always) ||
"CLOSE" >> pure(OmpMapTypeModifier::Value::Close) ||
"OMPX_HOLD" >> pure(OmpMapTypeModifier::Value::Ompx_Hold) ||
"PRESENT" >> pure(OmpMapTypeModifier::Value::Present)))
// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||
construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))
TYPE_PARSER(construct<OmpOrderModifier>(
"REPRODUCIBLE" >> pure(OmpOrderModifier::Value::Reproducible) ||
"UNCONSTRAINED" >> pure(OmpOrderModifier::Value::Unconstrained)))
TYPE_PARSER(construct<OmpOrderingModifier>(
"MONOTONIC" >> pure(OmpOrderingModifier::Value::Monotonic) ||
"NONMONOTONIC" >> pure(OmpOrderingModifier::Value::Nonmonotonic) ||
"SIMD" >> pure(OmpOrderingModifier::Value::Simd)))
TYPE_PARSER(construct<OmpPrescriptiveness>(
"STRICT" >> pure(OmpPrescriptiveness::Value::Strict)))
TYPE_PARSER(construct<OmpReductionModifier>(
"INSCAN" >> pure(OmpReductionModifier::Value::Inscan) ||
"TASK" >> pure(OmpReductionModifier::Value::Task) ||
"DEFAULT" >> pure(OmpReductionModifier::Value::Default)))
TYPE_PARSER(construct<OmpStepComplexModifier>( //
"STEP" >> parenthesized(scalarIntExpr)))
TYPE_PARSER(construct<OmpStepSimpleModifier>(scalarIntExpr))
TYPE_PARSER(construct<OmpTaskDependenceType>(
"DEPOBJ" >> pure(OmpTaskDependenceType::Value::Depobj) ||
"IN"_id >> pure(OmpTaskDependenceType::Value::In) ||
"INOUT"_id >> pure(OmpTaskDependenceType::Value::Inout) ||
"INOUTSET"_id >> pure(OmpTaskDependenceType::Value::Inoutset) ||
"MUTEXINOUTSET" >> pure(OmpTaskDependenceType::Value::Mutexinoutset) ||
"OUT" >> pure(OmpTaskDependenceType::Value::Out)))
TYPE_PARSER(construct<OmpVariableCategory>(
"AGGREGATE" >> pure(OmpVariableCategory::Value::Aggregate) ||
"ALL"_id >> pure(OmpVariableCategory::Value::All) ||
"ALLOCATABLE" >> pure(OmpVariableCategory::Value::Allocatable) ||
"POINTER" >> pure(OmpVariableCategory::Value::Pointer) ||
"SCALAR" >> pure(OmpVariableCategory::Value::Scalar)))
// This could be auto-generated.
TYPE_PARSER(
sourced(construct<OmpAffinityClause::Modifier>(Parser<OmpIterator>{})))
TYPE_PARSER(
sourced(construct<OmpAlignedClause::Modifier>(Parser<OmpAlignment>{})))
TYPE_PARSER(sourced(construct<OmpAllocateClause::Modifier>(sourced(
construct<OmpAllocateClause::Modifier>(Parser<OmpAlignModifier>{}) ||
construct<OmpAllocateClause::Modifier>(
Parser<OmpAllocatorComplexModifier>{}) ||
construct<OmpAllocateClause::Modifier>(
Parser<OmpAllocatorSimpleModifier>{})))))
TYPE_PARSER(sourced(
construct<OmpDefaultmapClause::Modifier>(Parser<OmpVariableCategory>{})))
TYPE_PARSER(sourced(construct<OmpDependClause::TaskDep::Modifier>(sourced(
construct<OmpDependClause::TaskDep::Modifier>(Parser<OmpIterator>{}) ||
construct<OmpDependClause::TaskDep::Modifier>(
Parser<OmpTaskDependenceType>{})))))
TYPE_PARSER(
sourced(construct<OmpDeviceClause::Modifier>(Parser<OmpDeviceModifier>{})))
TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>(
sourced(construct<OmpFromClause::Modifier>(Parser<OmpExpectation>{}) ||
construct<OmpFromClause::Modifier>(Parser<OmpMapper>{}) ||
construct<OmpFromClause::Modifier>(Parser<OmpIterator>{})))))
TYPE_PARSER(sourced(
construct<OmpGrainsizeClause::Modifier>(Parser<OmpPrescriptiveness>{})))
TYPE_PARSER(sourced(construct<OmpIfClause::Modifier>(OmpDirectiveNameParser{})))
TYPE_PARSER(sourced(construct<OmpInReductionClause::Modifier>(
Parser<OmpReductionIdentifier>{})))
TYPE_PARSER(sourced(construct<OmpLastprivateClause::Modifier>(
Parser<OmpLastprivateModifier>{})))
TYPE_PARSER(sourced(
construct<OmpLinearClause::Modifier>(Parser<OmpLinearModifier>{}) ||
construct<OmpLinearClause::Modifier>(Parser<OmpStepComplexModifier>{}) ||
construct<OmpLinearClause::Modifier>(Parser<OmpStepSimpleModifier>{})))
TYPE_PARSER(sourced(construct<OmpMapClause::Modifier>(
sourced(construct<OmpMapClause::Modifier>(Parser<OmpMapTypeModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpMapper>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpIterator>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpMapType>{})))))
TYPE_PARSER(
sourced(construct<OmpOrderClause::Modifier>(Parser<OmpOrderModifier>{})))
TYPE_PARSER(sourced(
construct<OmpNumTasksClause::Modifier>(Parser<OmpPrescriptiveness>{})))
TYPE_PARSER(sourced(construct<OmpReductionClause::Modifier>(sourced(
construct<OmpReductionClause::Modifier>(Parser<OmpReductionModifier>{}) ||
construct<OmpReductionClause::Modifier>(
Parser<OmpReductionIdentifier>{})))))
TYPE_PARSER(sourced(construct<OmpScheduleClause::Modifier>(sourced(
construct<OmpScheduleClause::Modifier>(Parser<OmpChunkModifier>{}) ||
construct<OmpScheduleClause::Modifier>(Parser<OmpOrderingModifier>{})))))
TYPE_PARSER(sourced(construct<OmpTaskReductionClause::Modifier>(
Parser<OmpReductionIdentifier>{})))
TYPE_PARSER(sourced(construct<OmpToClause::Modifier>(
sourced(construct<OmpToClause::Modifier>(Parser<OmpExpectation>{}) ||
construct<OmpToClause::Modifier>(Parser<OmpMapper>{}) ||
construct<OmpToClause::Modifier>(Parser<OmpIterator>{})))))
TYPE_PARSER(sourced(construct<OmpWhenClause::Modifier>( //
Parser<OmpContextSelector>{})))
// --- Parsers for clauses --------------------------------------------
/// `MOBClause` is a clause that has a
/// std::tuple<Modifiers, OmpObjectList, bool>.
/// Helper function to create a typical modifiers-objects clause, where the
/// commas separating individual modifiers are optional, and the clause
/// contains a bool member to indicate whether it was fully comma-separated
/// or not.
template <bool CommaSeparated, typename MOBClause>
static inline MOBClause makeMobClause(
std::list<typename MOBClause::Modifier> &&mods, OmpObjectList &&objs) {
if (!mods.empty()) {
return MOBClause{std::move(mods), std::move(objs), CommaSeparated};
} else {
using ListTy = std::list<typename MOBClause::Modifier>;
return MOBClause{std::optional<ListTy>{}, std::move(objs), CommaSeparated};
}
}
// [5.0] 2.10.1 affinity([aff-modifier:] locator-list)
// aff-modifier: interator-modifier
TYPE_PARSER(construct<OmpAffinityClause>(
maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
// 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
TYPE_PARSER(construct<OmpDefaultClause::DataSharingAttribute>(
"PRIVATE" >> pure(OmpDefaultClause::DataSharingAttribute::Private) ||
"FIRSTPRIVATE" >>
pure(OmpDefaultClause::DataSharingAttribute::Firstprivate) ||
"SHARED" >> pure(OmpDefaultClause::DataSharingAttribute::Shared) ||
"NONE" >> pure(OmpDefaultClause::DataSharingAttribute::None)))
TYPE_PARSER(construct<OmpDefaultClause>(
construct<OmpDefaultClause>(
Parser<OmpDefaultClause::DataSharingAttribute>{}) ||
construct<OmpDefaultClause>(indirect(Parser<OmpDirectiveSpecification>{}))))
// 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD)
TYPE_PARSER(construct<OmpProcBindClause>(
"CLOSE" >> pure(OmpProcBindClause::AffinityPolicy::Close) ||
"MASTER" >> pure(OmpProcBindClause::AffinityPolicy::Master) ||
"PRIMARY" >> pure(OmpProcBindClause::AffinityPolicy::Primary) ||
"SPREAD" >> pure(OmpProcBindClause::AffinityPolicy::Spread)))
TYPE_PARSER(construct<OmpMapClause>(
applyFunction<OmpMapClause>(makeMobClause<true>,
modifierList<OmpMapClause>(","_tok), Parser<OmpObjectList>{}) ||
applyFunction<OmpMapClause>(makeMobClause<false>,
modifierList<OmpMapClause>(maybe(","_tok)), Parser<OmpObjectList>{})))
// [OpenMP 5.0]
// 2.19.7.2 defaultmap(implicit-behavior[:variable-category])
// implicit-behavior -> ALLOC | TO | FROM | TOFROM | FIRSRTPRIVATE | NONE |
// DEFAULT
// variable-category -> ALL | SCALAR | AGGREGATE | ALLOCATABLE | POINTER
TYPE_PARSER(construct<OmpDefaultmapClause>(
construct<OmpDefaultmapClause::ImplicitBehavior>(
"ALLOC" >> pure(OmpDefaultmapClause::ImplicitBehavior::Alloc) ||
"TO"_id >> pure(OmpDefaultmapClause::ImplicitBehavior::To) ||
"FROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::From) ||
"TOFROM" >> pure(OmpDefaultmapClause::ImplicitBehavior::Tofrom) ||
"FIRSTPRIVATE" >>
pure(OmpDefaultmapClause::ImplicitBehavior::Firstprivate) ||
"NONE" >> pure(OmpDefaultmapClause::ImplicitBehavior::None) ||
"DEFAULT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Default)),
maybe(":" >> nonemptyList(Parser<OmpDefaultmapClause::Modifier>{}))))
TYPE_PARSER(construct<OmpScheduleClause::Kind>(
"STATIC" >> pure(OmpScheduleClause::Kind::Static) ||
"DYNAMIC" >> pure(OmpScheduleClause::Kind::Dynamic) ||
"GUIDED" >> pure(OmpScheduleClause::Kind::Guided) ||
"AUTO" >> pure(OmpScheduleClause::Kind::Auto) ||
"RUNTIME" >> pure(OmpScheduleClause::Kind::Runtime)))
TYPE_PARSER(construct<OmpScheduleClause>(
maybe(nonemptyList(Parser<OmpScheduleClause::Modifier>{}) / ":"),
Parser<OmpScheduleClause::Kind>{}, maybe("," >> scalarIntExpr)))
// device([ device-modifier :] scalar-integer-expression)
TYPE_PARSER(construct<OmpDeviceClause>(
maybe(nonemptyList(Parser<OmpDeviceClause::Modifier>{}) / ":"),
scalarIntExpr))
// device_type(any | host | nohost)
TYPE_PARSER(construct<OmpDeviceTypeClause>(
"ANY" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Any) ||
"HOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Host) ||
"NOHOST" >> pure(OmpDeviceTypeClause::DeviceTypeDescription::Nohost)))
// 2.12 IF (directive-name-modifier: scalar-logical-expr)
TYPE_PARSER(construct<OmpIfClause>(
maybe(nonemptyList(Parser<OmpIfClause::Modifier>{}) / ":"),
scalarLogicalExpr))
TYPE_PARSER(construct<OmpReductionClause>(
maybe(nonemptyList(Parser<OmpReductionClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
// OMP 5.0 2.19.5.6 IN_REDUCTION (reduction-identifier: variable-name-list)
TYPE_PARSER(construct<OmpInReductionClause>(
maybe(nonemptyList(Parser<OmpInReductionClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
TYPE_PARSER(construct<OmpTaskReductionClause>(
maybe(nonemptyList(Parser<OmpTaskReductionClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
// OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list)
// OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier
// [, allocate-modifier] :]
// variable-name-list)
// allocate-modifier -> allocator | align
TYPE_PARSER(construct<OmpAllocateClause>(
maybe(nonemptyList(Parser<OmpAllocateClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
// iteration-offset -> +/- non-negative-constant-expr
TYPE_PARSER(construct<OmpIterationOffset>(
Parser<DefinedOperator>{}, scalarIntConstantExpr))
// iteration -> iteration-variable [+/- nonnegative-scalar-integer-constant]
TYPE_PARSER(construct<OmpIteration>(name, maybe(Parser<OmpIterationOffset>{})))
TYPE_PARSER(construct<OmpIterationVector>(nonemptyList(Parser<OmpIteration>{})))
TYPE_PARSER(construct<OmpDoacross>(
construct<OmpDoacross>(construct<OmpDoacross::Sink>(
"SINK"_tok >> ":"_tok >> Parser<OmpIterationVector>{})) ||
construct<OmpDoacross>(construct<OmpDoacross::Source>("SOURCE"_tok))))
TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
construct<OmpDependClause>(
// Try to parse OmpDoacross first, because TaskDep will succeed on
// "sink: xxx", interpreting it to not have any modifiers, and "sink"
// being an OmpObject. Parsing of the TaskDep variant will stop right
// after the "sink", leaving the ": xxx" unvisited.
construct<OmpDependClause>(Parser<OmpDoacross>{}) ||
// Parse TaskDep after Doacross.
construct<OmpDependClause>(construct<OmpDependClause::TaskDep>(
maybe(nonemptyList(Parser<OmpDependClause::TaskDep::Modifier>{}) /
": "),
Parser<OmpObjectList>{}))))
TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US,
construct<OmpDoacrossClause>(Parser<OmpDoacross>{}))
TYPE_PARSER(construct<OmpFromClause>(
applyFunction<OmpFromClause>(makeMobClause<true>,
modifierList<OmpFromClause>(","_tok), Parser<OmpObjectList>{}) ||
applyFunction<OmpFromClause>(makeMobClause<false>,
modifierList<OmpFromClause>(maybe(","_tok)), Parser<OmpObjectList>{})))
TYPE_PARSER(construct<OmpToClause>(
applyFunction<OmpToClause>(makeMobClause<true>,
modifierList<OmpToClause>(","_tok), Parser<OmpObjectList>{}) ||
applyFunction<OmpToClause>(makeMobClause<false>,
modifierList<OmpToClause>(maybe(","_tok)), Parser<OmpObjectList>{})))
OmpLinearClause makeLinearFromOldSyntax(OmpLinearClause::Modifier &&lm,
OmpObjectList &&objs, std::optional<OmpLinearClause::Modifier> &&ssm) {
std::list<OmpLinearClause::Modifier> mods;
mods.emplace_back(std::move(lm));
if (ssm) {
mods.emplace_back(std::move(*ssm));
}
return OmpLinearClause{std::move(objs),
mods.empty() ? decltype(mods){} : std::move(mods),
/*PostModified=*/false};
}
TYPE_PARSER(
// Parse the "modifier(x)" first, because syntacticaly it will match
// an array element (i.e. a list item).
// LINEAR(linear-modifier(list) [: step-simple-modifier])
construct<OmpLinearClause>( //
applyFunction<OmpLinearClause>(makeLinearFromOldSyntax,
SpecificModifierParser<OmpLinearModifier, OmpLinearClause>{},
parenthesized(Parser<OmpObjectList>{}),
maybe(":"_tok >> SpecificModifierParser<OmpStepSimpleModifier,
OmpLinearClause>{}))) ||
// LINEAR(list [: modifiers])
construct<OmpLinearClause>( //
Parser<OmpObjectList>{},
maybe(":"_tok >> nonemptyList(Parser<OmpLinearClause::Modifier>{})),
/*PostModified=*/pure(true)))
// OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle)
TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{}))
// 2.8.1 ALIGNED (list: alignment)
TYPE_PARSER(construct<OmpAlignedClause>(Parser<OmpObjectList>{},
maybe(":" >> nonemptyList(Parser<OmpAlignedClause::Modifier>{}))))
TYPE_PARSER(construct<OmpUpdateClause>(
construct<OmpUpdateClause>(Parser<OmpDependenceType>{}) ||
construct<OmpUpdateClause>(Parser<OmpTaskDependenceType>{})))
TYPE_PARSER(construct<OmpOrderClause>(
maybe(nonemptyList(Parser<OmpOrderClause::Modifier>{}) / ":"),
"CONCURRENT" >> pure(OmpOrderClause::Ordering::Concurrent)))
TYPE_PARSER(construct<OmpMatchClause>(
Parser<traits::OmpContextSelectorSpecification>{}))
TYPE_PARSER(construct<OmpOtherwiseClause>(
maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
TYPE_PARSER(construct<OmpWhenClause>(
maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
TYPE_PARSER(construct<OmpGrainsizeClause>(
maybe(nonemptyList(Parser<OmpGrainsizeClause::Modifier>{}) / ":"),
scalarIntExpr))
// OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression)
TYPE_PARSER(construct<OmpNumTasksClause>(
maybe(nonemptyList(Parser<OmpNumTasksClause::Modifier>{}) / ":"),
scalarIntExpr))
TYPE_PARSER(
construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/"))
// OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list)
TYPE_PARSER(construct<OmpLastprivateClause>(
maybe(nonemptyList(Parser<OmpLastprivateClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
// OMP 5.2 11.7.1 BIND ( PARALLEL | TEAMS | THREAD )
TYPE_PARSER(construct<OmpBindClause>(
"PARALLEL" >> pure(OmpBindClause::Binding::Parallel) ||
"TEAMS" >> pure(OmpBindClause::Binding::Teams) ||
"THREAD" >> pure(OmpBindClause::Binding::Thread)))
TYPE_PARSER(construct<OmpAlignClause>(scalarIntExpr))
TYPE_PARSER(construct<OmpAtClause>(
"EXECUTION" >> pure(OmpAtClause::ActionTime::Execution) ||
"COMPILATION" >> pure(OmpAtClause::ActionTime::Compilation)))
TYPE_PARSER(construct<OmpSeverityClause>(
"FATAL" >> pure(OmpSeverityClause::Severity::Fatal) ||
"WARNING" >> pure(OmpSeverityClause::Severity::Warning)))
TYPE_PARSER(construct<OmpMessageClause>(expr))
TYPE_PARSER(
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
"ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
"AFFINITY" >> construct<OmpClause>(construct<OmpClause::Affinity>(
parenthesized(Parser<OmpAffinityClause>{}))) ||
"ALIGN" >> construct<OmpClause>(construct<OmpClause::Align>(
parenthesized(Parser<OmpAlignClause>{}))) ||
"ALIGNED" >> construct<OmpClause>(construct<OmpClause::Aligned>(
parenthesized(Parser<OmpAlignedClause>{}))) ||
"ALLOCATE" >> construct<OmpClause>(construct<OmpClause::Allocate>(
parenthesized(Parser<OmpAllocateClause>{}))) ||
"ALLOCATOR" >> construct<OmpClause>(construct<OmpClause::Allocator>(
parenthesized(scalarIntExpr))) ||
"AT" >> construct<OmpClause>(construct<OmpClause::At>(
parenthesized(Parser<OmpAtClause>{}))) ||
"ATOMIC_DEFAULT_MEM_ORDER" >>
construct<OmpClause>(construct<OmpClause::AtomicDefaultMemOrder>(
parenthesized(Parser<OmpAtomicDefaultMemOrderClause>{}))) ||
"BIND" >> construct<OmpClause>(construct<OmpClause::Bind>(
parenthesized(Parser<OmpBindClause>{}))) ||
"COLLAPSE" >> construct<OmpClause>(construct<OmpClause::Collapse>(
parenthesized(scalarIntConstantExpr))) ||
"COPYIN" >> construct<OmpClause>(construct<OmpClause::Copyin>(
parenthesized(Parser<OmpObjectList>{}))) ||
"COPYPRIVATE" >> construct<OmpClause>(construct<OmpClause::Copyprivate>(
(parenthesized(Parser<OmpObjectList>{})))) ||
"DEFAULT"_id >> construct<OmpClause>(construct<OmpClause::Default>(
parenthesized(Parser<OmpDefaultClause>{}))) ||
"DEFAULTMAP" >> construct<OmpClause>(construct<OmpClause::Defaultmap>(
parenthesized(Parser<OmpDefaultmapClause>{}))) ||
"DEPEND" >> construct<OmpClause>(construct<OmpClause::Depend>(
parenthesized(Parser<OmpDependClause>{}))) ||
"DESTROY" >>
construct<OmpClause>(construct<OmpClause::Destroy>(maybe(parenthesized(
construct<OmpDestroyClause>(Parser<OmpObject>{}))))) ||
"DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
parenthesized(Parser<OmpDeviceClause>{}))) ||
"DEVICE_TYPE" >> construct<OmpClause>(construct<OmpClause::DeviceType>(
parenthesized(Parser<OmpDeviceTypeClause>{}))) ||
"DIST_SCHEDULE" >>
construct<OmpClause>(construct<OmpClause::DistSchedule>(
parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||
"DOACROSS" >>
construct<OmpClause>(parenthesized(Parser<OmpDoacrossClause>{})) ||
"DYNAMIC_ALLOCATORS" >>
construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) ||
"ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>(
parenthesized(Parser<OmpObjectList>{}))) ||
"EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>(
parenthesized(Parser<OmpObjectList>{}))) ||
"FILTER" >> construct<OmpClause>(construct<OmpClause::Filter>(
parenthesized(scalarIntExpr))) ||
"FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
parenthesized(scalarLogicalExpr))) ||
"FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
parenthesized(Parser<OmpObjectList>{}))) ||
"FROM" >> construct<OmpClause>(construct<OmpClause::From>(
parenthesized(Parser<OmpFromClause>{}))) ||
"FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
"GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
parenthesized(Parser<OmpGrainsizeClause>{}))) ||
"HAS_DEVICE_ADDR" >>
construct<OmpClause>(construct<OmpClause::HasDeviceAddr>(
parenthesized(Parser<OmpObjectList>{}))) ||
"HINT" >> construct<OmpClause>(
construct<OmpClause::Hint>(parenthesized(constantExpr))) ||
"IF" >> construct<OmpClause>(construct<OmpClause::If>(
parenthesized(Parser<OmpIfClause>{}))) ||
"INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
"INCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Inclusive>(
parenthesized(Parser<OmpObjectList>{}))) ||
"IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
parenthesized(Parser<OmpObjectList>{}))) ||
"LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
parenthesized(Parser<OmpLastprivateClause>{}))) ||
"LINEAR" >> construct<OmpClause>(construct<OmpClause::Linear>(
parenthesized(Parser<OmpLinearClause>{}))) ||
"LINK" >> construct<OmpClause>(construct<OmpClause::Link>(
parenthesized(Parser<OmpObjectList>{}))) ||
"MAP" >> construct<OmpClause>(construct<OmpClause::Map>(
parenthesized(Parser<OmpMapClause>{}))) ||
"MATCH" >> construct<OmpClause>(construct<OmpClause::Match>(
parenthesized(Parser<OmpMatchClause>{}))) ||
"MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) ||
"MESSAGE" >> construct<OmpClause>(construct<OmpClause::Message>(
parenthesized(Parser<OmpMessageClause>{}))) ||
"NOCONTEXT" >> construct<OmpClause>(construct<OmpClause::Nocontext>(
parenthesized(scalarLogicalExpr))) ||
"NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) ||
"NONTEMPORAL" >> construct<OmpClause>(construct<OmpClause::Nontemporal>(
parenthesized(nonemptyList(name)))) ||
"NOTINBRANCH" >>
construct<OmpClause>(construct<OmpClause::Notinbranch>()) ||
"NOVARIANTS" >> construct<OmpClause>(construct<OmpClause::Novariants>(
parenthesized(scalarLogicalExpr))) ||
"NOWAIT" >> construct<OmpClause>(construct<OmpClause::Nowait>()) ||
"NUM_TASKS" >> construct<OmpClause>(construct<OmpClause::NumTasks>(
parenthesized(Parser<OmpNumTasksClause>{}))) ||
"NUM_TEAMS" >> construct<OmpClause>(construct<OmpClause::NumTeams>(
parenthesized(scalarIntExpr))) ||
"NUM_THREADS" >> construct<OmpClause>(construct<OmpClause::NumThreads>(
parenthesized(scalarIntExpr))) ||
"OMPX_BARE" >> construct<OmpClause>(construct<OmpClause::OmpxBare>()) ||
"ORDER" >> construct<OmpClause>(construct<OmpClause::Order>(
parenthesized(Parser<OmpOrderClause>{}))) ||
"ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>(
maybe(parenthesized(scalarIntConstantExpr)))) ||
"OTHERWISE" >> construct<OmpClause>(construct<OmpClause::Otherwise>(
maybe(parenthesized(Parser<OmpOtherwiseClause>{})))) ||
"PARTIAL" >> construct<OmpClause>(construct<OmpClause::Partial>(
maybe(parenthesized(scalarIntConstantExpr)))) ||
"PRIORITY" >> construct<OmpClause>(construct<OmpClause::Priority>(
parenthesized(scalarIntExpr))) ||
"PRIVATE" >> construct<OmpClause>(construct<OmpClause::Private>(
parenthesized(Parser<OmpObjectList>{}))) ||
"PROC_BIND" >> construct<OmpClause>(construct<OmpClause::ProcBind>(
parenthesized(Parser<OmpProcBindClause>{}))) ||
"REDUCTION"_id >> construct<OmpClause>(construct<OmpClause::Reduction>(
parenthesized(Parser<OmpReductionClause>{}))) ||
"IN_REDUCTION" >> construct<OmpClause>(construct<OmpClause::InReduction>(
parenthesized(Parser<OmpInReductionClause>{}))) ||
"DETACH" >> construct<OmpClause>(construct<OmpClause::Detach>(
parenthesized(Parser<OmpDetachClause>{}))) ||
"TASK_REDUCTION" >>
construct<OmpClause>(construct<OmpClause::TaskReduction>(
parenthesized(Parser<OmpTaskReductionClause>{}))) ||
"RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()) ||
"RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
"REVERSE_OFFLOAD" >>
construct<OmpClause>(construct<OmpClause::ReverseOffload>()) ||
"SAFELEN" >> construct<OmpClause>(construct<OmpClause::Safelen>(
parenthesized(scalarIntConstantExpr))) ||
"SCHEDULE" >> construct<OmpClause>(construct<OmpClause::Schedule>(
parenthesized(Parser<OmpScheduleClause>{}))) ||
"SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) ||
"SEVERITY" >> construct<OmpClause>(construct<OmpClause::Severity>(
parenthesized(Parser<OmpSeverityClause>{}))) ||
"SHARED" >> construct<OmpClause>(construct<OmpClause::Shared>(
parenthesized(Parser<OmpObjectList>{}))) ||
"SIMD"_id >> construct<OmpClause>(construct<OmpClause::Simd>()) ||
"SIMDLEN" >> construct<OmpClause>(construct<OmpClause::Simdlen>(
parenthesized(scalarIntConstantExpr))) ||
"SIZES" >> construct<OmpClause>(construct<OmpClause::Sizes>(
parenthesized(nonemptyList(scalarIntExpr)))) ||
"PERMUTATION" >> construct<OmpClause>(construct<OmpClause::Permutation>(
parenthesized(nonemptyList(scalarIntExpr)))) ||
"THREADS" >> construct<OmpClause>(construct<OmpClause::Threads>()) ||
"THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
parenthesized(scalarIntExpr))) ||
"TO" >> construct<OmpClause>(construct<OmpClause::To>(
parenthesized(Parser<OmpToClause>{}))) ||
"USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
parenthesized(Parser<OmpObjectList>{}))) ||
"USE_DEVICE_ADDR" >>
construct<OmpClause>(construct<OmpClause::UseDeviceAddr>(
parenthesized(Parser<OmpObjectList>{}))) ||
"UNIFIED_ADDRESS" >>
construct<OmpClause>(construct<OmpClause::UnifiedAddress>()) ||
"UNIFIED_SHARED_MEMORY" >>
construct<OmpClause>(construct<OmpClause::UnifiedSharedMemory>()) ||
"UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>(
parenthesized(nonemptyList(name)))) ||
"UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()) ||
"UPDATE" >> construct<OmpClause>(construct<OmpClause::Update>(
parenthesized(Parser<OmpUpdateClause>{}))) ||
"WHEN" >> construct<OmpClause>(construct<OmpClause::When>(
parenthesized(Parser<OmpWhenClause>{}))))
// [Clause, [Clause], ...]
TYPE_PARSER(sourced(construct<OmpClauseList>(
many(maybe(","_tok) >> sourced(Parser<OmpClause>{})))))
// 2.1 (variable | /common-block/ | array-sections)
TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{})))
TYPE_PARSER(sourced(construct<OmpErrorDirective>(
verbatim("ERROR"_tok), Parser<OmpClauseList>{})))
// --- Parsers for directives and constructs --------------------------
TYPE_PARSER(sourced(construct<OmpDirectiveSpecification>( //
OmpDirectiveNameParser{},
maybe(parenthesized(nonemptyList(Parser<OmpArgument>{}))),
maybe(Parser<OmpClauseList>{}))))
TYPE_PARSER(sourced(construct<OmpNothingDirective>("NOTHING" >> ok)))
TYPE_PARSER(sourced(construct<OpenMPUtilityConstruct>(
sourced(construct<OpenMPUtilityConstruct>(
sourced(Parser<OmpErrorDirective>{}))) ||
sourced(construct<OpenMPUtilityConstruct>(
sourced(Parser<OmpNothingDirective>{}))))))
TYPE_PARSER(sourced(construct<OmpMetadirectiveDirective>(
"METADIRECTIVE" >> Parser<OmpClauseList>{})))
// Omp directives enclosing do loop
TYPE_PARSER(sourced(construct<OmpLoopDirective>(first(
"DISTRIBUTE PARALLEL DO SIMD" >>
pure(llvm::omp::Directive::OMPD_distribute_parallel_do_simd),
"DISTRIBUTE PARALLEL DO" >>
pure(llvm::omp::Directive::OMPD_distribute_parallel_do),
"DISTRIBUTE SIMD" >> pure(llvm::omp::Directive::OMPD_distribute_simd),
"DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_distribute),
"DO SIMD" >> pure(llvm::omp::Directive::OMPD_do_simd),
"DO" >> pure(llvm::omp::Directive::OMPD_do),
"LOOP" >> pure(llvm::omp::Directive::OMPD_loop),
"MASKED TASKLOOP SIMD" >>
pure(llvm::omp::Directive::OMPD_masked_taskloop_simd),
"MASKED TASKLOOP" >> pure(llvm::omp::Directive::OMPD_masked_taskloop),
"MASTER TASKLOOP SIMD" >>
pure(llvm::omp::Directive::OMPD_master_taskloop_simd),
"MASTER TASKLOOP" >> pure(llvm::omp::Directive::OMPD_master_taskloop),
"PARALLEL DO SIMD" >> pure(llvm::omp::Directive::OMPD_parallel_do_simd),
"PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_parallel_do),
"PARALLEL MASKED TASKLOOP SIMD" >>
pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop_simd),
"PARALLEL MASKED TASKLOOP" >>
pure(llvm::omp::Directive::OMPD_parallel_masked_taskloop),
"PARALLEL MASTER TASKLOOP SIMD" >>
pure(llvm::omp::Directive::OMPD_parallel_master_taskloop_simd),
"PARALLEL MASTER TASKLOOP" >>
pure(llvm::omp::Directive::OMPD_parallel_master_taskloop),
"SIMD" >> pure(llvm::omp::Directive::OMPD_simd),
"TARGET LOOP" >> pure(llvm::omp::Directive::OMPD_target_loop),
"TARGET PARALLEL DO SIMD" >>
pure(llvm::omp::Directive::OMPD_target_parallel_do_simd),
"TARGET PARALLEL DO" >> pure(llvm::omp::Directive::OMPD_target_parallel_do),
"TARGET PARALLEL LOOP" >>
pure(llvm::omp::Directive::OMPD_target_parallel_loop),
"TARGET SIMD" >> pure(llvm::omp::Directive::OMPD_target_simd),
"TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
pure(llvm::omp::Directive::
OMPD_target_teams_distribute_parallel_do_simd),
"TARGET TEAMS DISTRIBUTE PARALLEL DO" >>
pure(llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do),
"TARGET TEAMS DISTRIBUTE SIMD" >>
pure(llvm::omp::Directive::OMPD_target_teams_distribute_simd),
"TARGET TEAMS DISTRIBUTE" >>
pure(llvm::omp::Directive::OMPD_target_teams_distribute),
"TARGET TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_target_teams_loop),
"TASKLOOP SIMD" >> pure(llvm::omp::Directive::OMPD_taskloop_simd),
"TASKLOOP" >> pure(llvm::omp::Directive::OMPD_taskloop),
"TEAMS DISTRIBUTE PARALLEL DO SIMD" >>
pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd),
"TEAMS DISTRIBUTE PARALLEL DO" >>
pure(llvm::omp::Directive::OMPD_teams_distribute_parallel_do),
"TEAMS DISTRIBUTE SIMD" >>
pure(llvm::omp::Directive::OMPD_teams_distribute_simd),
"TEAMS DISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_teams_distribute),
"TEAMS LOOP" >> pure(llvm::omp::Directive::OMPD_teams_loop),
"TILE" >> pure(llvm::omp::Directive::OMPD_tile),
"UNROLL" >> pure(llvm::omp::Directive::OMPD_unroll)))))
TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>(
sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{})))
// 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP
TYPE_PARSER(sourced(construct<OmpCancelType>(
first("PARALLEL" >> pure(OmpCancelType::Type::Parallel),
"SECTIONS" >> pure(OmpCancelType::Type::Sections),
"DO" >> pure(OmpCancelType::Type::Do),
"TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup)))))
// 2.14.2 Cancellation Point construct
TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>(
verbatim("CANCELLATION POINT"_tok), Parser<OmpCancelType>{})))
// 2.14.1 Cancel construct
TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(verbatim("CANCEL"_tok),
Parser<OmpCancelType>{}, maybe("IF" >> parenthesized(scalarLogicalExpr)))))
TYPE_PARSER(sourced(construct<OmpFailClause>(
parenthesized(indirect(Parser<OmpMemoryOrderClause>{})))))
// 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
// memory-order-clause ->
// seq_cst
// acq_rel
// release
// acquire
// relaxed
TYPE_PARSER(sourced(construct<OmpMemoryOrderClause>(
sourced("SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) ||
"ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
"RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
"RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>())))))
// 2.4 Requires construct [OpenMP 5.0]
// atomic-default-mem-order-clause ->
// seq_cst
// acq_rel
// relaxed
TYPE_PARSER(construct<OmpAtomicDefaultMemOrderClause>(
"SEQ_CST" >> pure(common::OmpAtomicDefaultMemOrderType::SeqCst) ||
"ACQ_REL" >> pure(common::OmpAtomicDefaultMemOrderType::AcqRel) ||
"RELAXED" >> pure(common::OmpAtomicDefaultMemOrderType::Relaxed)))
// 2.17.7 Atomic construct
// atomic-clause -> memory-order-clause | HINT(hint-expression)
TYPE_PARSER(sourced(construct<OmpAtomicClause>(
construct<OmpAtomicClause>(Parser<OmpMemoryOrderClause>{}) ||
construct<OmpAtomicClause>("FAIL" >> Parser<OmpFailClause>{}) ||
construct<OmpAtomicClause>("HINT" >>
sourced(construct<OmpClause>(
construct<OmpClause::Hint>(parenthesized(constantExpr))))))))
// atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
TYPE_PARSER(sourced(construct<OmpAtomicClauseList>(
many(maybe(","_tok) >> sourced(Parser<OmpAtomicClause>{})))))
TYPE_PARSER(sourced(construct<OpenMPDepobjConstruct>(verbatim("DEPOBJ"_tok),
parenthesized(Parser<OmpObject>{}), sourced(Parser<OmpClause>{}))))
TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok),
many(maybe(","_tok) >> sourced(Parser<OmpMemoryOrderClause>{})),
maybe(parenthesized(Parser<OmpObjectList>{})))))
// Simple Standalone Directives
TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
"BARRIER" >> pure(llvm::omp::Directive::OMPD_barrier),
"ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
"SCAN" >> pure(llvm::omp::Directive::OMPD_scan),
"TARGET ENTER DATA" >> pure(llvm::omp::Directive::OMPD_target_enter_data),
"TARGET EXIT DATA" >> pure(llvm::omp::Directive::OMPD_target_exit_data),
"TARGET UPDATE" >> pure(llvm::omp::Directive::OMPD_target_update),
"TASKWAIT" >> pure(llvm::omp::Directive::OMPD_taskwait),
"TASKYIELD" >> pure(llvm::omp::Directive::OMPD_taskyield)))))
TYPE_PARSER(sourced(construct<OpenMPSimpleStandaloneConstruct>(
Parser<OmpSimpleStandaloneDirective>{}, Parser<OmpClauseList>{})))
// Standalone Constructs
TYPE_PARSER(
sourced(construct<OpenMPStandaloneConstruct>(
Parser<OpenMPSimpleStandaloneConstruct>{}) ||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
construct<OpenMPStandaloneConstruct>(
Parser<OpenMPCancellationPointConstruct>{}) ||
construct<OpenMPStandaloneConstruct>(
Parser<OmpMetadirectiveDirective>{}) ||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{})) /
endOfLine)
// Directives enclosing structured-block
TYPE_PARSER(construct<OmpBlockDirective>(first(
"MASKED" >> pure(llvm::omp::Directive::OMPD_masked),
"MASTER" >> pure(llvm::omp::Directive::OMPD_master),
"ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
"PARALLEL MASKED" >> pure(llvm::omp::Directive::OMPD_parallel_masked),
"PARALLEL MASTER" >> pure(llvm::omp::Directive::OMPD_parallel_master),
"PARALLEL WORKSHARE" >> pure(llvm::omp::Directive::OMPD_parallel_workshare),
"PARALLEL" >> pure(llvm::omp::Directive::OMPD_parallel),
"SCOPE" >> pure(llvm::omp::Directive::OMPD_scope),
"SINGLE" >> pure(llvm::omp::Directive::OMPD_single),
"TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data),
"TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel),
"TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams),
"TARGET" >> pure(llvm::omp::Directive::OMPD_target),
"TASK"_id >> pure(llvm::omp::Directive::OMPD_task),
"TASKGROUP" >> pure(llvm::omp::Directive::OMPD_taskgroup),
"TEAMS" >> pure(llvm::omp::Directive::OMPD_teams),
"WORKSHARE" >> pure(llvm::omp::Directive::OMPD_workshare))))
TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>(
sourced(Parser<OmpBlockDirective>{}), Parser<OmpClauseList>{})))
TYPE_PARSER(construct<OmpReductionInitializerClause>(
"INITIALIZER" >> parenthesized("OMP_PRIV =" >> expr)))
// 2.16 Declare Reduction Construct
TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
verbatim("DECLARE REDUCTION"_tok),
"(" >> indirect(Parser<OmpReductionSpecifier>{}) / ")",
maybe(Parser<OmpReductionInitializerClause>{}))))
// declare-target with list
TYPE_PARSER(sourced(construct<OmpDeclareTargetWithList>(
parenthesized(Parser<OmpObjectList>{}))))
// declare-target with clause
TYPE_PARSER(
sourced(construct<OmpDeclareTargetWithClause>(Parser<OmpClauseList>{})))
// declare-target-specifier
TYPE_PARSER(
construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithList>{}) ||
construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithClause>{}))
// 2.10.6 Declare Target Construct
TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
verbatim("DECLARE TARGET"_tok), Parser<OmpDeclareTargetSpecifier>{})))
// mapper-specifier
TYPE_PARSER(construct<OmpMapperSpecifier>(
maybe(name / ":" / !":"_tok), typeSpec / "::", name))
// OpenMP 5.2: 5.8.8 Declare Mapper Construct
TYPE_PARSER(sourced(
construct<OpenMPDeclareMapperConstruct>(verbatim("DECLARE MAPPER"_tok),
parenthesized(Parser<OmpMapperSpecifier>{}), Parser<OmpClauseList>{})))
TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) ||
construct<OmpReductionCombiner>(Parser<FunctionReference>{}))
// 2.17.7 atomic -> ATOMIC [clause [,]] atomic-clause [[,] clause] |
// ATOMIC [clause]
// clause -> memory-order-clause | HINT(hint-expression)
// memory-order-clause -> SEQ_CST | ACQ_REL | RELEASE | ACQUIRE | RELAXED
// atomic-clause -> READ | WRITE | UPDATE | CAPTURE
// OMP END ATOMIC
TYPE_PARSER(construct<OmpEndAtomic>(startOmpLine >> "END ATOMIC"_tok))
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] READ [MEMORY-ORDER-CLAUSE-LIST]
TYPE_PARSER("ATOMIC" >>
sourced(construct<OmpAtomicRead>(
Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("READ"_tok),
Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
maybe(Parser<OmpEndAtomic>{} / endOmpLine))))
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] CAPTURE [MEMORY-ORDER-CLAUSE-LIST]
TYPE_PARSER("ATOMIC" >>
sourced(construct<OmpAtomicCapture>(
Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("CAPTURE"_tok),
Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
statement(assignmentStmt), Parser<OmpEndAtomic>{} / endOmpLine)))
TYPE_PARSER(construct<OmpAtomicCompareIfStmt>(indirect(Parser<IfStmt>{})) ||
construct<OmpAtomicCompareIfStmt>(indirect(Parser<IfConstruct>{})))
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] COMPARE [MEMORY-ORDER-CLAUSE-LIST]
TYPE_PARSER("ATOMIC" >>
sourced(construct<OmpAtomicCompare>(
Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("COMPARE"_tok),
Parser<OmpAtomicClauseList>{} / endOmpLine,
Parser<OmpAtomicCompareIfStmt>{},
maybe(Parser<OmpEndAtomic>{} / endOmpLine))))
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST]
TYPE_PARSER("ATOMIC" >>
sourced(construct<OmpAtomicUpdate>(
Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("UPDATE"_tok),
Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
maybe(Parser<OmpEndAtomic>{} / endOmpLine))))
// OMP ATOMIC [atomic-clause-list]
TYPE_PARSER(sourced(construct<OmpAtomic>(verbatim("ATOMIC"_tok),
Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
maybe(Parser<OmpEndAtomic>{} / endOmpLine))))
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] WRITE [MEMORY-ORDER-CLAUSE-LIST]
TYPE_PARSER("ATOMIC" >>
sourced(construct<OmpAtomicWrite>(
Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("WRITE"_tok),
Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
maybe(Parser<OmpEndAtomic>{} / endOmpLine))))
// Atomic Construct
TYPE_PARSER(construct<OpenMPAtomicConstruct>(Parser<OmpAtomicRead>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCapture>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCompare>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicWrite>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicUpdate>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomic>{}))
// 2.13.2 OMP CRITICAL
TYPE_PARSER(startOmpLine >>
sourced(construct<OmpEndCriticalDirective>(
verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) /
endOmpLine)
TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok),
maybe(parenthesized(name)), Parser<OmpClauseList>{})) /
endOmpLine)
TYPE_PARSER(construct<OpenMPCriticalConstruct>(
Parser<OmpCriticalDirective>{}, block, Parser<OmpEndCriticalDirective>{}))
TYPE_PARSER(sourced(construct<OmpDispatchDirective>(
verbatim("DISPATCH"_tok), Parser<OmpClauseList>{})))
TYPE_PARSER(
construct<OmpEndDispatchDirective>(startOmpLine >> "END DISPATCH"_tok))
TYPE_PARSER(sourced(construct<OpenMPDispatchConstruct>(
Parser<OmpDispatchDirective>{} / endOmpLine, block,
maybe(Parser<OmpEndDispatchDirective>{} / endOmpLine))))
// 2.11.3 Executable Allocate directive
TYPE_PARSER(
sourced(construct<OpenMPExecutableAllocate>(verbatim("ALLOCATE"_tok),
maybe(parenthesized(Parser<OmpObjectList>{})), Parser<OmpClauseList>{},
maybe(nonemptyList(Parser<OpenMPDeclarativeAllocate>{})) / endOmpLine,
statement(allocateStmt))))
// 6.7 Allocators construct [OpenMP 5.2]
// allocators-construct -> ALLOCATORS [allocate-clause [,]]
// allocate-stmt
// [omp-end-allocators-construct]
TYPE_PARSER(sourced(construct<OpenMPAllocatorsConstruct>(
verbatim("ALLOCATORS"_tok), Parser<OmpClauseList>{} / endOmpLine,
statement(allocateStmt), maybe(Parser<OmpEndAllocators>{} / endOmpLine))))
TYPE_PARSER(construct<OmpEndAllocators>(startOmpLine >> "END ALLOCATORS"_tok))
// 2.8.2 Declare Simd construct
TYPE_PARSER(
sourced(construct<OpenMPDeclareSimdConstruct>(verbatim("DECLARE SIMD"_tok),
maybe(parenthesized(name)), Parser<OmpClauseList>{})))
// 2.4 Requires construct
TYPE_PARSER(sourced(construct<OpenMPRequiresConstruct>(
verbatim("REQUIRES"_tok), Parser<OmpClauseList>{})))
// 2.15.2 Threadprivate directive
TYPE_PARSER(sourced(construct<OpenMPThreadprivate>(
verbatim("THREADPRIVATE"_tok), parenthesized(Parser<OmpObjectList>{}))))
// 2.11.3 Declarative Allocate directive
TYPE_PARSER(
sourced(construct<OpenMPDeclarativeAllocate>(verbatim("ALLOCATE"_tok),
parenthesized(Parser<OmpObjectList>{}), Parser<OmpClauseList>{})) /
lookAhead(endOmpLine / !statement(allocateStmt)))
// Declarative constructs
TYPE_PARSER(startOmpLine >>
withMessage("expected OpenMP construct"_err_en_US,
sourced(construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPDeclareReductionConstruct>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPDeclareMapperConstruct>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPDeclareSimdConstruct>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPDeclareTargetConstruct>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPDeclarativeAllocate>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPRequiresConstruct>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPThreadprivate>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OpenMPUtilityConstruct>{}) ||
construct<OpenMPDeclarativeConstruct>(
Parser<OmpMetadirectiveDirective>{})) /
endOmpLine))
// Block Construct
TYPE_PARSER(construct<OpenMPBlockConstruct>(
Parser<OmpBeginBlockDirective>{} / endOmpLine, block,
Parser<OmpEndBlockDirective>{} / endOmpLine))
// OMP SECTIONS Directive
TYPE_PARSER(construct<OmpSectionsDirective>(first(
"SECTIONS" >> pure(llvm::omp::Directive::OMPD_sections),
"PARALLEL SECTIONS" >> pure(llvm::omp::Directive::OMPD_parallel_sections))))
// OMP BEGIN and END SECTIONS Directive
TYPE_PARSER(sourced(construct<OmpBeginSectionsDirective>(
sourced(Parser<OmpSectionsDirective>{}), Parser<OmpClauseList>{})))
TYPE_PARSER(
startOmpLine >> sourced(construct<OmpEndSectionsDirective>(
sourced("END"_tok >> Parser<OmpSectionsDirective>{}),
Parser<OmpClauseList>{})))
// OMP SECTION-BLOCK
TYPE_PARSER(construct<OpenMPSectionConstruct>(block))
TYPE_PARSER(maybe(startOmpLine >> "SECTION"_tok / endOmpLine) >>
construct<OmpSectionBlocks>(nonemptySeparated(
construct<OpenMPConstruct>(sourced(Parser<OpenMPSectionConstruct>{})),
startOmpLine >> "SECTION"_tok / endOmpLine)))
// OMP SECTIONS (OpenMP 5.0 - 2.8.1), PARALLEL SECTIONS (OpenMP 5.0 - 2.13.3)
TYPE_PARSER(construct<OpenMPSectionsConstruct>(
Parser<OmpBeginSectionsDirective>{} / endOmpLine,
Parser<OmpSectionBlocks>{}, Parser<OmpEndSectionsDirective>{} / endOmpLine))
TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
startOmpLine >>
withMessage("expected OpenMP construct"_err_en_US,
first(construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}),
// OpenMPBlockConstruct is attempted before
// OpenMPStandaloneConstruct to resolve !$OMP ORDERED
construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPUtilityConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPDispatchConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPExecutableAllocate>{}),
construct<OpenMPConstruct>(Parser<OpenMPAllocatorsConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPDeclarativeAllocate>{}),
construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}))))
// END OMP Block directives
TYPE_PARSER(
startOmpLine >> sourced(construct<OmpEndBlockDirective>(
sourced("END"_tok >> Parser<OmpBlockDirective>{}),
Parser<OmpClauseList>{})))
// END OMP Loop directives
TYPE_PARSER(
startOmpLine >> sourced(construct<OmpEndLoopDirective>(
sourced("END"_tok >> Parser<OmpLoopDirective>{}),
Parser<OmpClauseList>{})))
TYPE_PARSER(construct<OpenMPLoopConstruct>(
Parser<OmpBeginLoopDirective>{} / endOmpLine))
} // namespace Fortran::parser