
This is the first part of the effort to make parsing of clause modifiers more uniform and robust. Currently, when multiple modifiers are allowed, the parser will expect them to appear in a hard-coded order. Additionally, modifier properties (such as "ultimate") are checked separately for each case. The overall plan is 1. Extract all modifiers into their own top-level classes, and then equip them with sets of common properties that will allow performing the property checks generically, without refering to the specific kind of the modifier. 2. Define a parser (as a separate class) for each modifier. 3. For each clause define a union (std::variant) of all allowable modifiers, and parse the modifiers as a list of these unions. The intent is also to isolate parts of the code that could eventually be auto-generated. OpenMP modifier overhaul: #1/3
1070 lines
51 KiB
C++
1070 lines
51 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"
|
|
|
|
// OpenMP Directives and Clauses
|
|
namespace Fortran::parser {
|
|
|
|
constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok;
|
|
constexpr auto endOmpLine = space >> endOfLine;
|
|
|
|
// Helper class to deal with a list of modifiers of various types.
|
|
// The list (to be parsed) is assumed to start with all modifiers of the
|
|
// first type, followed by a list of modifiers of the second type, etc.
|
|
// Each list can be empty, e.g.
|
|
// mod_of_kind_2, mod_of_kind_3, mod_of_kind_5, ...
|
|
// The result type is a tuple of optional lists of each modifier type.
|
|
template <typename Separator, typename Parser, typename... Parsers>
|
|
struct ConcatSeparated {
|
|
template <typename P>
|
|
using OptListOf = std::optional<std::list<typename P::resultType>>;
|
|
template <typename P> using TupleFor = std::tuple<OptListOf<P>>;
|
|
|
|
using resultType = std::tuple<OptListOf<Parser>, OptListOf<Parsers>...>;
|
|
|
|
constexpr ConcatSeparated(ConcatSeparated &&) = default;
|
|
constexpr ConcatSeparated(const ConcatSeparated &) = default;
|
|
constexpr ConcatSeparated(Separator sep, Parser p, Parsers... ps)
|
|
: parser_(p), sepAndParsers_(sep, ps...) {}
|
|
|
|
std::optional<resultType> Parse(ParseState &state) const {
|
|
// firstParser is a list parser, it returns optional<list>.
|
|
auto firstParser =
|
|
attempt(nonemptySeparated(parser_, std::get<0>(sepAndParsers_)));
|
|
|
|
if constexpr (sizeof...(Parsers) == 0) {
|
|
return TupleFor<Parser>{std::move(firstParser.Parse(state))};
|
|
} else {
|
|
using restParserType = ConcatSeparated<Separator, Parsers...>;
|
|
auto restParser = std::make_from_tuple<restParserType>(sepAndParsers_);
|
|
|
|
if (auto first{firstParser.Parse(state)}) {
|
|
if (attempt(std::get<0>(sepAndParsers_)).Parse(state)) {
|
|
return std::tuple_cat(TupleFor<Parser>(std::move(*first)),
|
|
std::move(*restParser.Parse(state)));
|
|
}
|
|
return std::tuple_cat(TupleFor<Parser>{std::move(*first)},
|
|
std::tuple<OptListOf<Parsers>...>{});
|
|
}
|
|
return std::tuple_cat(
|
|
TupleFor<Parser>{}, std::move(*restParser.Parse(state)));
|
|
}
|
|
}
|
|
|
|
private:
|
|
const Parser parser_;
|
|
const std::tuple<Separator, Parsers...> sepAndParsers_;
|
|
};
|
|
|
|
// Map modifiers come from four categories:
|
|
// - map-type-modifier,
|
|
// - mapper (not parsed yet),
|
|
// - iterator,
|
|
// - map-type.
|
|
// There can be zero or more map-type-modifiers, and zero or one modifier
|
|
// of every other kind.
|
|
// Syntax-wise they look like a single list, where the last element could
|
|
// be a map-type, and all elements in that list are comma-separated[1].
|
|
// Only if there was at least one modifier (of any kind) specified, the
|
|
// list must end with ":".
|
|
// There are complications coming from the fact that the comma separating the
|
|
// two kinds of modifiers is only allowed if there is at least one modifier of
|
|
// each kind. The MapModifiers parser utilizes the ConcatSeparated parser, which
|
|
// takes care of that. ConcatSeparated returns a tuple with optional lists of
|
|
// modifiers for every type.
|
|
// [1] Any of the commas are optional, but that syntax has been deprecated
|
|
// in OpenMP 5.2, and the parsing code keeps a record of whether the commas
|
|
// were present.
|
|
template <typename Separator> struct MapModifiers {
|
|
constexpr MapModifiers(Separator sep) : sep_(sep) {}
|
|
constexpr MapModifiers(const MapModifiers &) = default;
|
|
constexpr MapModifiers(MapModifiers &&) = default;
|
|
|
|
// Parsing of mappers is not supported yet.
|
|
using TypeModParser = Parser<OmpMapClause::TypeModifier>;
|
|
using IterParser = Parser<OmpIterator>;
|
|
using TypeParser = Parser<OmpMapClause::Type>;
|
|
using ModParser =
|
|
ConcatSeparated<Separator, TypeModParser, IterParser, TypeParser>;
|
|
|
|
using resultType = typename ModParser::resultType;
|
|
|
|
std::optional<resultType> Parse(ParseState &state) const {
|
|
auto mp = ModParser(sep_, TypeModParser{}, IterParser{}, TypeParser{});
|
|
auto mods = mp.Parse(state);
|
|
// The ModParser always "succeeds", i.e. even if the input is junk, it
|
|
// will return a tuple filled with nullopts. If any of the components
|
|
// is not a nullopt, expect a ":".
|
|
if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) {
|
|
if (!attempt(":"_tok).Parse(state)) {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
return std::move(mods);
|
|
}
|
|
|
|
private:
|
|
const Separator sep_;
|
|
};
|
|
|
|
// This is almost exactly the same thing as MapModifiers. It has the same
|
|
// issue (it expects modifiers in a specific order), and the fix for that
|
|
// will change how modifiers are parsed. Instead of making this code more
|
|
// generic, make it simple, and generalize after the fix is in place.
|
|
template <typename Separator> struct MotionModifiers {
|
|
constexpr MotionModifiers(Separator sep) : sep_(sep) {}
|
|
constexpr MotionModifiers(const MotionModifiers &) = default;
|
|
constexpr MotionModifiers(MotionModifiers &&) = default;
|
|
|
|
using ExpParser = Parser<OmpFromClause::Expectation>;
|
|
using IterParser = Parser<OmpIterator>;
|
|
using ModParser = ConcatSeparated<Separator, ExpParser, IterParser>;
|
|
|
|
using resultType = typename ModParser::resultType;
|
|
|
|
std::optional<resultType> Parse(ParseState &state) const {
|
|
auto mp{ModParser(sep_, ExpParser{}, IterParser{})};
|
|
auto mods{mp.Parse(state)};
|
|
// The ModParser always "succeeds", i.e. even if the input is junk, it
|
|
// will return a tuple filled with nullopts. If any of the components
|
|
// is not a nullopt, expect a ":".
|
|
if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) {
|
|
if (!attempt(":"_tok).Parse(state)) {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
return std::move(mods);
|
|
}
|
|
|
|
private:
|
|
const Separator sep_;
|
|
};
|
|
|
|
// OpenMP Clauses
|
|
|
|
// [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple |
|
|
// identifier = subscript-triple
|
|
// [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 clause modifiers -----------------------------------
|
|
|
|
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))
|
|
|
|
TYPE_PARSER(construct<OmpDependenceType>(
|
|
"SINK" >> pure(OmpDependenceType::Value::Sink) ||
|
|
"SOURCE" >> pure(OmpDependenceType::Value::Source)))
|
|
|
|
// [5.0] 2.1.6 iterator -> iterator-specifier-list
|
|
TYPE_PARSER(construct<OmpIterator>("ITERATOR" >>
|
|
parenthesized(nonemptyList(sourced(Parser<OmpIteratorSpecifier>{})))))
|
|
|
|
// 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)))
|
|
|
|
// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
|
|
TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||
|
|
construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))
|
|
|
|
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)))
|
|
|
|
// --- Parsers for clauses --------------------------------------------
|
|
|
|
// [5.0] 2.10.1 affinity([aff-modifier:] locator-list)
|
|
// aff-modifier: interator-modifier
|
|
TYPE_PARSER(construct<OmpAffinityClause>(
|
|
maybe(Parser<OmpIterator>{} / ":"), Parser<OmpObjectList>{}))
|
|
|
|
// 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
|
|
TYPE_PARSER(construct<OmpDefaultClause>(
|
|
"PRIVATE" >> pure(OmpDefaultClause::Type::Private) ||
|
|
"FIRSTPRIVATE" >> pure(OmpDefaultClause::Type::Firstprivate) ||
|
|
"SHARED" >> pure(OmpDefaultClause::Type::Shared) ||
|
|
"NONE" >> pure(OmpDefaultClause::Type::None)))
|
|
|
|
// 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD )
|
|
TYPE_PARSER(construct<OmpProcBindClause>(
|
|
"CLOSE" >> pure(OmpProcBindClause::Type::Close) ||
|
|
"MASTER" >> pure(OmpProcBindClause::Type::Master) ||
|
|
"PRIMARY" >> pure(OmpProcBindClause::Type::Primary) ||
|
|
"SPREAD" >> pure(OmpProcBindClause::Type::Spread)))
|
|
|
|
// 2.15.5.1 map ->
|
|
// MAP ([ [map-type-modifiers [,] ] map-type : ] variable-name-list)
|
|
// map-type-modifiers -> map-type-modifier [,] [...]
|
|
// map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT
|
|
// map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM
|
|
TYPE_PARSER(construct<OmpMapClause::TypeModifier>(
|
|
"ALWAYS" >> pure(OmpMapClause::TypeModifier::Always) ||
|
|
"CLOSE" >> pure(OmpMapClause::TypeModifier::Close) ||
|
|
"OMPX_HOLD" >> pure(OmpMapClause::TypeModifier::Ompx_Hold) ||
|
|
"PRESENT" >> pure(OmpMapClause::TypeModifier::Present)))
|
|
|
|
TYPE_PARSER(
|
|
construct<OmpMapClause::Type>("ALLOC" >> pure(OmpMapClause::Type::Alloc) ||
|
|
"DELETE" >> pure(OmpMapClause::Type::Delete) ||
|
|
"FROM" >> pure(OmpMapClause::Type::From) ||
|
|
"RELEASE" >> pure(OmpMapClause::Type::Release) ||
|
|
"TO"_id >> pure(OmpMapClause::Type::To) ||
|
|
"TOFROM" >> pure(OmpMapClause::Type::Tofrom)))
|
|
|
|
template <bool CommasEverywhere>
|
|
static inline OmpMapClause makeMapClause(OmpMapperIdentifier &&mm,
|
|
std::tuple<std::optional<std::list<OmpMapClause::TypeModifier>>,
|
|
std::optional<std::list<OmpIterator>>,
|
|
std::optional<std::list<OmpMapClause::Type>>> &&mods,
|
|
OmpObjectList &&objs) {
|
|
auto &&[tm, it, ty] = std::move(mods);
|
|
return OmpMapClause{std::move(mm), std::move(tm), std::move(it),
|
|
std::move(ty), std::move(objs), CommasEverywhere};
|
|
}
|
|
|
|
TYPE_PARSER(construct<OmpMapperIdentifier>(
|
|
maybe("MAPPER"_tok >> parenthesized(name) / ","_tok)))
|
|
|
|
TYPE_PARSER(construct<OmpMapClause>(
|
|
applyFunction<OmpMapClause>(makeMapClause<true>,
|
|
Parser<OmpMapperIdentifier>{}, MapModifiers(","_tok),
|
|
Parser<OmpObjectList>{}) ||
|
|
applyFunction<OmpMapClause>(makeMapClause<false>,
|
|
Parser<OmpMapperIdentifier>{}, MapModifiers(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(":" >>
|
|
construct<OmpDefaultmapClause::VariableCategory>(
|
|
"ALL"_id >> pure(OmpDefaultmapClause::VariableCategory::All) ||
|
|
"SCALAR" >> pure(OmpDefaultmapClause::VariableCategory::Scalar) ||
|
|
"AGGREGATE" >>
|
|
pure(OmpDefaultmapClause::VariableCategory::Aggregate) ||
|
|
"ALLOCATABLE" >>
|
|
pure(OmpDefaultmapClause::VariableCategory::Allocatable) ||
|
|
"POINTER" >>
|
|
pure(OmpDefaultmapClause::VariableCategory::Pointer)))))
|
|
|
|
// 2.7.1 SCHEDULE ([modifier1 [, modifier2]:]kind[, chunk_size])
|
|
// Modifier -> MONITONIC | NONMONOTONIC | SIMD
|
|
// kind -> STATIC | DYNAMIC | GUIDED | AUTO | RUNTIME
|
|
// chunk_size -> ScalarIntExpr
|
|
TYPE_PARSER(construct<OmpScheduleModifierType>(
|
|
"MONOTONIC" >> pure(OmpScheduleModifierType::ModType::Monotonic) ||
|
|
"NONMONOTONIC" >> pure(OmpScheduleModifierType::ModType::Nonmonotonic) ||
|
|
"SIMD" >> pure(OmpScheduleModifierType::ModType::Simd)))
|
|
|
|
TYPE_PARSER(construct<OmpScheduleModifier>(Parser<OmpScheduleModifierType>{},
|
|
maybe("," >> Parser<OmpScheduleModifierType>{}) / ":"))
|
|
|
|
TYPE_PARSER(construct<OmpScheduleClause>(maybe(Parser<OmpScheduleModifier>{}),
|
|
"STATIC" >> pure(OmpScheduleClause::ScheduleType::Static) ||
|
|
"DYNAMIC" >> pure(OmpScheduleClause::ScheduleType::Dynamic) ||
|
|
"GUIDED" >> pure(OmpScheduleClause::ScheduleType::Guided) ||
|
|
"AUTO" >> pure(OmpScheduleClause::ScheduleType::Auto) ||
|
|
"RUNTIME" >> pure(OmpScheduleClause::ScheduleType::Runtime),
|
|
maybe("," >> scalarIntExpr)))
|
|
|
|
// device([ device-modifier :] scalar-integer-expression)
|
|
TYPE_PARSER(construct<OmpDeviceClause>(
|
|
maybe(
|
|
("ANCESTOR" >> pure(OmpDeviceClause::DeviceModifier::Ancestor) ||
|
|
"DEVICE_NUM" >> pure(OmpDeviceClause::DeviceModifier::Device_Num)) /
|
|
":"),
|
|
scalarIntExpr))
|
|
|
|
// device_type(any | host | nohost)
|
|
TYPE_PARSER(construct<OmpDeviceTypeClause>(
|
|
"ANY" >> pure(OmpDeviceTypeClause::Type::Any) ||
|
|
"HOST" >> pure(OmpDeviceTypeClause::Type::Host) ||
|
|
"NOHOST" >> pure(OmpDeviceTypeClause::Type::Nohost)))
|
|
|
|
// 2.12 IF (directive-name-modifier: scalar-logical-expr)
|
|
TYPE_PARSER(construct<OmpIfClause>(
|
|
maybe(
|
|
("PARALLEL" >> pure(OmpIfClause::DirectiveNameModifier::Parallel) ||
|
|
"SIMD" >> pure(OmpIfClause::DirectiveNameModifier::Simd) ||
|
|
"TARGET ENTER DATA" >>
|
|
pure(OmpIfClause::DirectiveNameModifier::TargetEnterData) ||
|
|
"TARGET EXIT DATA" >>
|
|
pure(OmpIfClause::DirectiveNameModifier::TargetExitData) ||
|
|
"TARGET DATA" >>
|
|
pure(OmpIfClause::DirectiveNameModifier::TargetData) ||
|
|
"TARGET UPDATE" >>
|
|
pure(OmpIfClause::DirectiveNameModifier::TargetUpdate) ||
|
|
"TARGET" >> pure(OmpIfClause::DirectiveNameModifier::Target) ||
|
|
"TASK"_id >> pure(OmpIfClause::DirectiveNameModifier::Task) ||
|
|
"TASKLOOP" >> pure(OmpIfClause::DirectiveNameModifier::Taskloop) ||
|
|
"TEAMS" >> pure(OmpIfClause::DirectiveNameModifier::Teams)) /
|
|
":"),
|
|
scalarLogicalExpr))
|
|
|
|
TYPE_PARSER(construct<OmpReductionClause>(
|
|
maybe(
|
|
("INSCAN" >> pure(OmpReductionClause::ReductionModifier::Inscan) ||
|
|
"TASK" >> pure(OmpReductionClause::ReductionModifier::Task) ||
|
|
"DEFAULT" >> pure(OmpReductionClause::ReductionModifier::Default)) /
|
|
","),
|
|
Parser<OmpReductionIdentifier>{} / ":", Parser<OmpObjectList>{}))
|
|
|
|
// OMP 5.0 2.19.5.6 IN_REDUCTION (reduction-identifier: variable-name-list)
|
|
TYPE_PARSER(construct<OmpInReductionClause>(
|
|
Parser<OmpReductionIdentifier>{} / ":", 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(
|
|
first(
|
|
construct<OmpAllocateClause::AllocateModifier>("ALLOCATOR" >>
|
|
construct<OmpAllocateClause::AllocateModifier::ComplexModifier>(
|
|
parenthesized(construct<
|
|
OmpAllocateClause::AllocateModifier::Allocator>(
|
|
scalarIntExpr)) /
|
|
",",
|
|
"ALIGN" >> parenthesized(construct<
|
|
OmpAllocateClause::AllocateModifier::Align>(
|
|
scalarIntExpr)))),
|
|
construct<OmpAllocateClause::AllocateModifier>("ALLOCATOR" >>
|
|
parenthesized(
|
|
construct<OmpAllocateClause::AllocateModifier::Allocator>(
|
|
scalarIntExpr))),
|
|
construct<OmpAllocateClause::AllocateModifier>("ALIGN" >>
|
|
parenthesized(
|
|
construct<OmpAllocateClause::AllocateModifier::Align>(
|
|
scalarIntExpr))),
|
|
construct<OmpAllocateClause::AllocateModifier>(
|
|
construct<OmpAllocateClause::AllocateModifier::Allocator>(
|
|
scalarIntExpr))) /
|
|
":"),
|
|
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>(
|
|
construct<OmpDependClause>(construct<OmpDependClause::TaskDep>(
|
|
maybe(Parser<OmpIterator>{} / ","_tok),
|
|
Parser<OmpTaskDependenceType>{} / ":", Parser<OmpObjectList>{})) ||
|
|
construct<OmpDependClause>(Parser<OmpDoacross>{})))
|
|
|
|
TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US,
|
|
construct<OmpDoacrossClause>(Parser<OmpDoacross>{}))
|
|
|
|
TYPE_PARSER(construct<OmpFromClause::Expectation>(
|
|
"PRESENT" >> pure(OmpFromClause::Expectation::Present)))
|
|
|
|
template <typename MotionClause, bool CommasEverywhere>
|
|
static inline MotionClause makeMotionClause(
|
|
std::tuple<std::optional<std::list<typename MotionClause::Expectation>>,
|
|
std::optional<std::list<OmpIterator>>> &&mods,
|
|
OmpObjectList &&objs) {
|
|
auto &&[exp, iter] = std::move(mods);
|
|
return MotionClause(
|
|
std::move(exp), std::move(iter), std::move(objs), CommasEverywhere);
|
|
}
|
|
|
|
TYPE_PARSER(construct<OmpFromClause>(
|
|
applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, true>,
|
|
MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
|
|
applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, false>,
|
|
MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))
|
|
|
|
TYPE_PARSER(construct<OmpToClause>(
|
|
applyFunction<OmpToClause>(makeMotionClause<OmpToClause, true>,
|
|
MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
|
|
applyFunction<OmpToClause>(makeMotionClause<OmpToClause, false>,
|
|
MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))
|
|
|
|
TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US,
|
|
construct<OmpLinearClause>(
|
|
construct<OmpLinearClause>(construct<OmpLinearClause::WithModifier>(
|
|
Parser<OmpLinearModifier>{}, parenthesized(nonemptyList(name)),
|
|
maybe(":" >> scalarIntConstantExpr))) ||
|
|
construct<OmpLinearClause>(construct<OmpLinearClause::WithoutModifier>(
|
|
nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))))
|
|
|
|
// 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(":" >> scalarIntConstantExpr)))
|
|
|
|
TYPE_PARSER(construct<OmpUpdateClause>(
|
|
construct<OmpUpdateClause>(Parser<OmpDependenceType>{}) ||
|
|
construct<OmpUpdateClause>(Parser<OmpTaskDependenceType>{})))
|
|
|
|
// 2.9.5 ORDER ([order-modifier :]concurrent)
|
|
TYPE_PARSER(construct<OmpOrderModifier>(
|
|
"REPRODUCIBLE" >> pure(OmpOrderModifier::Kind::Reproducible)) ||
|
|
construct<OmpOrderModifier>(
|
|
"UNCONSTRAINED" >> pure(OmpOrderModifier::Kind::Unconstrained)))
|
|
|
|
TYPE_PARSER(construct<OmpOrderClause>(maybe(Parser<OmpOrderModifier>{} / ":"),
|
|
"CONCURRENT" >> pure(OmpOrderClause::Type::Concurrent)))
|
|
|
|
// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
|
|
TYPE_PARSER(construct<OmpGrainsizeClause>(
|
|
maybe("STRICT" >> pure(OmpGrainsizeClause::Prescriptiveness::Strict) / ":"),
|
|
scalarIntExpr))
|
|
|
|
// OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression)
|
|
TYPE_PARSER(construct<OmpNumTasksClause>(
|
|
maybe("STRICT" >> pure(OmpNumTasksClause::Prescriptiveness::Strict) / ":"),
|
|
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("CONDITIONAL" >>
|
|
pure(OmpLastprivateClause::LastprivateModifier::Conditional) / ":"),
|
|
Parser<OmpObjectList>{}))
|
|
|
|
// OMP 5.2 11.7.1 BIND ( PARALLEL | TEAMS | THREAD )
|
|
TYPE_PARSER(construct<OmpBindClause>(
|
|
"PARALLEL" >> pure(OmpBindClause::Type::Parallel) ||
|
|
"TEAMS" >> pure(OmpBindClause::Type::Teams) ||
|
|
"THREAD" >> pure(OmpBindClause::Type::Thread)))
|
|
|
|
TYPE_PARSER(
|
|
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
|
|
"ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
|
|
"AFFINITY" >> construct<OmpClause>(construct<OmpClause::Affinity>(
|
|
parenthesized(Parser<OmpAffinityClause>{}))) ||
|
|
"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))) ||
|
|
"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>{}))) ||
|
|
"MERGEABLE" >> construct<OmpClause>(construct<OmpClause::Mergeable>()) ||
|
|
"NOGROUP" >> construct<OmpClause>(construct<OmpClause::Nogroup>()) ||
|
|
"NONTEMPORAL" >> construct<OmpClause>(construct<OmpClause::Nontemporal>(
|
|
parenthesized(nonemptyList(name)))) ||
|
|
"NOTINBRANCH" >>
|
|
construct<OmpClause>(construct<OmpClause::Notinbranch>()) ||
|
|
"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))) ||
|
|
"ORDER" >> construct<OmpClause>(construct<OmpClause::Order>(
|
|
parenthesized(Parser<OmpOrderClause>{}))) ||
|
|
"ORDERED" >> construct<OmpClause>(construct<OmpClause::Ordered>(
|
|
maybe(parenthesized(scalarIntConstantExpr)))) ||
|
|
"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" >> 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<OmpReductionClause>{}))) ||
|
|
"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>()) ||
|
|
"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>{}))))
|
|
|
|
// [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>{})))
|
|
|
|
// 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)))))
|
|
|
|
// 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>("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<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),
|
|
"(" >> Parser<OmpReductionIdentifier>{} / ":",
|
|
nonemptyList(Parser<DeclarationTypeSpec>{}) / ":",
|
|
Parser<OmpReductionCombiner>{} / ")",
|
|
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>{})))
|
|
|
|
// declare-mapper-specifier
|
|
TYPE_PARSER(construct<OmpDeclareMapperSpecifier>(
|
|
maybe(name / ":" / !":"_tok), typeSpec / "::", name))
|
|
|
|
// OpenMP 5.2: 5.8.8 Declare Mapper Construct
|
|
TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>(
|
|
verbatim("DECLARE MAPPER"_tok),
|
|
"(" >> Parser<OmpDeclareMapperSpecifier>{} / ")", Parser<OmpClauseList>{})))
|
|
|
|
TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) ||
|
|
construct<OmpReductionCombiner>(
|
|
construct<OmpReductionCombiner::FunctionCombiner>(
|
|
construct<Call>(Parser<ProcedureDesignator>{},
|
|
parenthesized(optionalList(actualArgSpec))))))
|
|
|
|
// 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)))
|
|
|
|
// 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<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>{}))
|
|
|
|
// 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>{})) /
|
|
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<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
|