
Add parser support for the new AUTOMAP modifier for OpenMP Declare Target Enter clause introduced in OpenMP 6.0 section 7.9.7.
1349 lines
41 KiB
C++
1349 lines
41 KiB
C++
//===- ClauseT.h -- clause template definitions ---------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// This file contains template classes that represent OpenMP clauses, as
|
|
// described in the OpenMP API specification.
|
|
//
|
|
// The general structure of any specific clause class is that it is either
|
|
// empty, or it consists of a single data member, which can take one of these
|
|
// three forms:
|
|
// - a value member, named `v`, or
|
|
// - a tuple of values, named `t`, or
|
|
// - a variant (i.e. union) of values, named `u`.
|
|
// To assist with generic visit algorithms, classes define one of the following
|
|
// traits:
|
|
// - EmptyTrait: the class has no data members.
|
|
// - WrapperTrait: the class has a single member `v`
|
|
// - TupleTrait: the class has a tuple member `t`
|
|
// - UnionTrait the class has a variant member `u`
|
|
// - IncompleteTrait: the class is a placeholder class that is currently empty,
|
|
// but will be completed at a later time.
|
|
// Note: This structure follows the one used in flang parser.
|
|
//
|
|
// The types used in the class definitions follow the names used in the spec
|
|
// (there are a few exceptions to this). For example, given
|
|
// Clause `foo`
|
|
// - foo-modifier : description...
|
|
// - list : list of variables
|
|
// the corresponding class would be
|
|
// template <...>
|
|
// struct FooT {
|
|
// using FooModifier = type that can represent the modifier
|
|
// using List = ListT<ObjectT<...>>;
|
|
// using TupleTrait = std::true_type;
|
|
// std::tuple<std::optional<FooModifier>, List> t;
|
|
// };
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef LLVM_FRONTEND_OPENMP_CLAUSET_H
|
|
#define LLVM_FRONTEND_OPENMP_CLAUSET_H
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/Frontend/OpenMP/OMP.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <optional>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <variant>
|
|
|
|
#define ENUM(Name, ...) enum class Name { __VA_ARGS__ }
|
|
#define OPT(x) std::optional<x>
|
|
|
|
// A number of OpenMP clauses contain values that come from a given set of
|
|
// possibilities. In the IR these are usually represented by enums. Both
|
|
// clang and flang use different types for the enums, and the enum elements
|
|
// representing the same thing may have different values between clang and
|
|
// flang.
|
|
// Since the representation below tries to adhere to the spec, and be source
|
|
// language agnostic, it defines its own enums, independent from any language
|
|
// frontend. As a consequence, when instantiating the templates below,
|
|
// frontend-specific enums need to be translated into the representation
|
|
// used here. The macros below are intended to assist with the conversion.
|
|
|
|
// Helper macro for enum-class conversion.
|
|
#define CLAUSET_SCOPED_ENUM_MEMBER_CONVERT(Ov, Tv) \
|
|
if (v == OtherEnum::Ov) { \
|
|
return ThisEnum::Tv; \
|
|
}
|
|
|
|
// Helper macro for enum (non-class) conversion.
|
|
#define CLAUSET_UNSCOPED_ENUM_MEMBER_CONVERT(Ov, Tv) \
|
|
if (v == Ov) { \
|
|
return ThisEnum::Tv; \
|
|
}
|
|
|
|
#define CLAUSET_ENUM_CONVERT(func, OtherE, ThisE, Maps) \
|
|
auto func = [](OtherE v) -> ThisE { \
|
|
using ThisEnum = ThisE; \
|
|
using OtherEnum = OtherE; \
|
|
(void)sizeof(OtherEnum); /*Avoid "unused local typedef" warning*/ \
|
|
Maps; \
|
|
llvm_unreachable("Unexpected value in " #OtherE); \
|
|
}
|
|
|
|
// Usage:
|
|
//
|
|
// Given two enums,
|
|
// enum class Other { o1, o2 };
|
|
// enum class This { t1, t2 };
|
|
// generate conversion function "Func : Other -> This" with
|
|
// CLAUSET_ENUM_CONVERT(
|
|
// Func, Other, This,
|
|
// CLAUSET_ENUM_MEMBER_CONVERT(o1, t1) // <- No comma
|
|
// CLAUSET_ENUM_MEMBER_CONVERT(o2, t2)
|
|
// ...
|
|
// )
|
|
//
|
|
// Note that the sequence of M(other-value, this-value) is separated
|
|
// with _spaces_, not commas.
|
|
|
|
namespace detail {
|
|
// Type trait to determine whether T is a specialization of std::variant.
|
|
template <typename T> struct is_variant {
|
|
static constexpr bool value = false;
|
|
};
|
|
|
|
template <typename... Ts> struct is_variant<std::variant<Ts...>> {
|
|
static constexpr bool value = true;
|
|
};
|
|
|
|
template <typename T> constexpr bool is_variant_v = is_variant<T>::value;
|
|
|
|
// Helper utility to create a type which is a union of two given variants.
|
|
template <typename...> struct UnionOfTwo;
|
|
|
|
template <typename... Types1, typename... Types2>
|
|
struct UnionOfTwo<std::variant<Types1...>, std::variant<Types2...>> {
|
|
using type = std::variant<Types1..., Types2...>;
|
|
};
|
|
} // namespace detail
|
|
|
|
namespace tomp {
|
|
namespace type {
|
|
|
|
// Helper utility to create a type which is a union of an arbitrary number
|
|
// of variants.
|
|
template <typename...> struct Union;
|
|
|
|
template <> struct Union<> {
|
|
// Legal to define, illegal to instantiate.
|
|
using type = std::variant<>;
|
|
};
|
|
|
|
template <typename T, typename... Ts> struct Union<T, Ts...> {
|
|
static_assert(detail::is_variant_v<T>);
|
|
using type =
|
|
typename detail::UnionOfTwo<T, typename Union<Ts...>::type>::type;
|
|
};
|
|
|
|
template <typename T> using ListT = llvm::SmallVector<T, 0>;
|
|
|
|
// The ObjectT class represents a variable or a locator (as defined in
|
|
// the OpenMP spec).
|
|
// Note: the ObjectT template is not defined. Any user of it is expected to
|
|
// provide their own specialization that conforms to the requirements listed
|
|
// below.
|
|
//
|
|
// Let ObjectS be any specialization of ObjectT:
|
|
//
|
|
// ObjectS must provide the following definitions:
|
|
// {
|
|
// using IdTy = Id;
|
|
// using ExprTy = Expr;
|
|
//
|
|
// auto id() const -> IdTy {
|
|
// // Return a value such that a.id() == b.id() if and only if:
|
|
// // (1) both `a` and `b` represent the same variable or location, or
|
|
// // (2) bool(a.id()) == false and bool(b.id()) == false
|
|
// }
|
|
// }
|
|
//
|
|
// The type IdTy should be hashable (usable as key in unordered containers).
|
|
//
|
|
// Values of type IdTy should be contextually convertible to `bool`.
|
|
//
|
|
// If S is an object of type ObjectS, then `bool(S.id())` is `false` if
|
|
// and only if S does not represent any variable or location.
|
|
//
|
|
// ObjectS should be copyable, movable, and default-constructible.
|
|
template <typename IdType, typename ExprType> struct ObjectT;
|
|
|
|
// By default, object equality is only determined by its identity.
|
|
template <typename I, typename E>
|
|
bool operator==(const ObjectT<I, E> &o1, const ObjectT<I, E> &o2) {
|
|
return o1.id() == o2.id();
|
|
}
|
|
|
|
template <typename I, typename E> using ObjectListT = ListT<ObjectT<I, E>>;
|
|
|
|
using DirectiveName = llvm::omp::Directive;
|
|
|
|
template <typename I, typename E> //
|
|
struct DefinedOperatorT {
|
|
struct DefinedOpName {
|
|
using WrapperTrait = std::true_type;
|
|
ObjectT<I, E> v;
|
|
};
|
|
ENUM(IntrinsicOperator, Power, Multiply, Divide, Add, Subtract, Concat, LT,
|
|
LE, EQ, NE, GE, GT, NOT, AND, OR, EQV, NEQV, Min, Max);
|
|
using UnionTrait = std::true_type;
|
|
std::variant<DefinedOpName, IntrinsicOperator> u;
|
|
};
|
|
|
|
// V5.2: [3.2.6] `iterator` modifier
|
|
template <typename E> //
|
|
struct RangeT {
|
|
// range-specification: begin : end[: step]
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<E, E, OPT(E)> t;
|
|
};
|
|
|
|
// V5.2: [3.2.6] `iterator` modifier
|
|
template <typename TypeType, typename IdType, typename ExprType> //
|
|
struct IteratorSpecifierT {
|
|
// iterators-specifier: [ iterator-type ] identifier = range-specification
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(TypeType), ObjectT<IdType, ExprType>, RangeT<ExprType>> t;
|
|
};
|
|
|
|
// Note:
|
|
// For motion or map clauses the OpenMP spec allows a unique mapper modifier.
|
|
// In practice, since these clauses apply to multiple objects, there can be
|
|
// multiple effective mappers applicable to these objects (due to overloads,
|
|
// etc.). Because of that store a list of mappers every time a mapper modifier
|
|
// is allowed. If the mapper list contains a single element, it applies to
|
|
// all objects in the clause, otherwise there should be as many mappers as
|
|
// there are objects.
|
|
// V5.2: [5.8.2] Mapper identifiers and `mapper` modifiers
|
|
template <typename I, typename E> //
|
|
struct MapperT {
|
|
using MapperIdentifier = ObjectT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
MapperIdentifier v;
|
|
};
|
|
|
|
// V5.2: [15.8.1] `memory-order` clauses
|
|
// When used as arguments for other clauses, e.g. `fail`.
|
|
ENUM(MemoryOrder, AcqRel, Acquire, Relaxed, Release, SeqCst);
|
|
ENUM(MotionExpectation, Present);
|
|
// Union of `dependence-type` and `task-depenence-type`.
|
|
// V5.2: [15.9.1] `task-dependence-type` modifier
|
|
ENUM(DependenceType, Depobj, In, Inout, Inoutset, Mutexinoutset, Out, Sink,
|
|
Source);
|
|
ENUM(Prescriptiveness, Strict);
|
|
|
|
template <typename I, typename E> //
|
|
struct LoopIterationT {
|
|
struct Distance {
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<DefinedOperatorT<I, E>, E> t;
|
|
};
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<ObjectT<I, E>, OPT(Distance)> t;
|
|
};
|
|
|
|
template <typename I, typename E> //
|
|
struct ProcedureDesignatorT {
|
|
using WrapperTrait = std::true_type;
|
|
ObjectT<I, E> v;
|
|
};
|
|
|
|
// Note:
|
|
// For reduction clauses the OpenMP spec allows a unique reduction identifier.
|
|
// For reasons analogous to those listed for the MapperT type, clauses that
|
|
// according to the spec contain a reduction identifier will contain a list of
|
|
// reduction identifiers. The same constraints apply: there is either a single
|
|
// identifier that applies to all objects, or there are as many identifiers
|
|
// as there are objects.
|
|
template <typename I, typename E> //
|
|
struct ReductionIdentifierT {
|
|
using UnionTrait = std::true_type;
|
|
std::variant<DefinedOperatorT<I, E>, ProcedureDesignatorT<I, E>> u;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
using IteratorT = ListT<IteratorSpecifierT<T, I, E>>;
|
|
|
|
template <typename T>
|
|
std::enable_if_t<T::EmptyTrait::value, bool> operator==(const T &a,
|
|
const T &b) {
|
|
return true;
|
|
}
|
|
template <typename T>
|
|
std::enable_if_t<T::IncompleteTrait::value, bool> operator==(const T &a,
|
|
const T &b) {
|
|
return true;
|
|
}
|
|
template <typename T>
|
|
std::enable_if_t<T::WrapperTrait::value, bool> operator==(const T &a,
|
|
const T &b) {
|
|
return a.v == b.v;
|
|
}
|
|
template <typename T>
|
|
std::enable_if_t<T::TupleTrait::value, bool> operator==(const T &a,
|
|
const T &b) {
|
|
return a.t == b.t;
|
|
}
|
|
template <typename T>
|
|
std::enable_if_t<T::UnionTrait::value, bool> operator==(const T &a,
|
|
const T &b) {
|
|
return a.u == b.u;
|
|
}
|
|
} // namespace type
|
|
|
|
template <typename T> using ListT = type::ListT<T>;
|
|
|
|
template <typename I, typename E> using ObjectT = type::ObjectT<I, E>;
|
|
template <typename I, typename E> using ObjectListT = type::ObjectListT<I, E>;
|
|
|
|
template <typename T, typename I, typename E>
|
|
using IteratorT = type::IteratorT<T, I, E>;
|
|
|
|
template <
|
|
typename ContainerTy, typename FunctionTy,
|
|
typename ElemTy = typename llvm::remove_cvref_t<ContainerTy>::value_type,
|
|
typename ResultTy = std::invoke_result_t<FunctionTy, ElemTy>>
|
|
ListT<ResultTy> makeList(ContainerTy &&container, FunctionTy &&func) {
|
|
ListT<ResultTy> v;
|
|
llvm::transform(container, std::back_inserter(v), func);
|
|
return v;
|
|
}
|
|
|
|
namespace clause {
|
|
using type::operator==;
|
|
|
|
// V5.2: [8.3.1] `assumption` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct AbsentT {
|
|
using List = ListT<type::DirectiveName>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [15.8.1] `memory-order` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct AcqRelT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [15.8.1] `memory-order` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct AcquireT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [7.5.2] `adjust_args` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AdjustArgsT {
|
|
using IncompleteTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [12.5.1] `affinity` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AffinityT {
|
|
using Iterator = type::IteratorT<T, I, E>;
|
|
using LocatorList = ObjectListT<I, E>;
|
|
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(Iterator), LocatorList> t;
|
|
};
|
|
|
|
// V5.2: [6.3] `align` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AlignT {
|
|
using Alignment = E;
|
|
|
|
using WrapperTrait = std::true_type;
|
|
Alignment v;
|
|
};
|
|
|
|
// V5.2: [5.11] `aligned` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AlignedT {
|
|
using Alignment = E;
|
|
using List = ObjectListT<I, E>;
|
|
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(Alignment), List> t;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
struct AllocatorT;
|
|
|
|
// V5.2: [6.6] `allocate` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AllocateT {
|
|
// AllocatorSimpleModifier is same as AllocatorComplexModifier.
|
|
using AllocatorComplexModifier = AllocatorT<T, I, E>;
|
|
using AlignModifier = AlignT<T, I, E>;
|
|
using List = ObjectListT<I, E>;
|
|
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(AllocatorComplexModifier), OPT(AlignModifier), List> t;
|
|
};
|
|
|
|
// V5.2: [6.4] `allocator` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AllocatorT {
|
|
using Allocator = E;
|
|
using WrapperTrait = std::true_type;
|
|
Allocator v;
|
|
};
|
|
|
|
// V5.2: [7.5.3] `append_args` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AppendArgsT {
|
|
using IncompleteTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.1] `at` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct AtT {
|
|
ENUM(ActionTime, Compilation, Execution);
|
|
using WrapperTrait = std::true_type;
|
|
ActionTime v;
|
|
};
|
|
|
|
// V5.2: [8.2.1] `requirement` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct AtomicDefaultMemOrderT {
|
|
using MemoryOrder = type::MemoryOrder;
|
|
using WrapperTrait = std::true_type;
|
|
MemoryOrder v; // Name not provided in spec
|
|
};
|
|
|
|
// V5.2: [11.7.1] `bind` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct BindT {
|
|
ENUM(Binding, Teams, Parallel, Thread);
|
|
using WrapperTrait = std::true_type;
|
|
Binding v;
|
|
};
|
|
|
|
// V5.2: [15.8.3] `extended-atomic` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct CaptureT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [4.4.3] `collapse` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct CollapseT {
|
|
using N = E;
|
|
using WrapperTrait = std::true_type;
|
|
N v;
|
|
};
|
|
|
|
// V5.2: [15.8.3] `extended-atomic` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct CompareT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.3.1] `assumption` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct ContainsT {
|
|
using List = ListT<type::DirectiveName>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [5.7.1] `copyin` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct CopyinT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [5.7.2] `copyprivate` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct CopyprivateT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [5.4.1] `default` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DefaultT {
|
|
ENUM(DataSharingAttribute, Firstprivate, None, Private, Shared);
|
|
using WrapperTrait = std::true_type;
|
|
DataSharingAttribute v;
|
|
};
|
|
|
|
// V5.2: [5.8.7] `defaultmap` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DefaultmapT {
|
|
ENUM(ImplicitBehavior, Alloc, To, From, Tofrom, Firstprivate, None, Default,
|
|
Present);
|
|
ENUM(VariableCategory, All, Scalar, Aggregate, Pointer, Allocatable);
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<ImplicitBehavior, OPT(VariableCategory)> t;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
struct DoacrossT;
|
|
|
|
// V5.2: [15.9.5] `depend` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DependT {
|
|
using Iterator = type::IteratorT<T, I, E>;
|
|
using LocatorList = ObjectListT<I, E>;
|
|
using DependenceType = tomp::type::DependenceType;
|
|
|
|
struct TaskDep { // The form with task dependence type.
|
|
using TupleTrait = std::true_type;
|
|
// Empty LocatorList means "omp_all_memory".
|
|
std::tuple<DependenceType, OPT(Iterator), LocatorList> t;
|
|
};
|
|
|
|
using Doacross = DoacrossT<T, I, E>;
|
|
using UnionTrait = std::true_type;
|
|
std::variant<Doacross, TaskDep> u; // Doacross form is legacy
|
|
};
|
|
|
|
// V5.2: [3.5] `destroy` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DestroyT {
|
|
using DestroyVar = ObjectT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
// DestroyVar can be ommitted in "depobj destroy".
|
|
OPT(DestroyVar) v;
|
|
};
|
|
|
|
// V5.2: [12.5.2] `detach` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DetachT {
|
|
using EventHandle = ObjectT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
EventHandle v;
|
|
};
|
|
|
|
// V5.2: [13.2] `device` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DeviceT {
|
|
using DeviceDescription = E;
|
|
ENUM(DeviceModifier, Ancestor, DeviceNum);
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(DeviceModifier), DeviceDescription> t;
|
|
};
|
|
|
|
// V5.2: [13.1] `device_type` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DeviceTypeT {
|
|
ENUM(DeviceTypeDescription, Any, Host, Nohost);
|
|
using WrapperTrait = std::true_type;
|
|
DeviceTypeDescription v;
|
|
};
|
|
|
|
// V5.2: [11.6.1] `dist_schedule` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DistScheduleT {
|
|
ENUM(Kind, Static);
|
|
using ChunkSize = E;
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<Kind, OPT(ChunkSize)> t;
|
|
};
|
|
|
|
// V5.2: [15.9.6] `doacross` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct DoacrossT {
|
|
using Vector = ListT<type::LoopIterationT<I, E>>;
|
|
using DependenceType = tomp::type::DependenceType;
|
|
using TupleTrait = std::true_type;
|
|
// Empty Vector means "omp_cur_iteration"
|
|
std::tuple<DependenceType, Vector> t;
|
|
};
|
|
|
|
// V5.2: [8.2.1] `requirement` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct DynamicAllocatorsT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [5.8.4] `enter` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct EnterT {
|
|
using List = ObjectListT<I, E>;
|
|
ENUM(Modifier, Automap);
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(Modifier), List> t;
|
|
};
|
|
|
|
// V5.2: [5.6.2] `exclusive` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct ExclusiveT {
|
|
using WrapperTrait = std::true_type;
|
|
using List = ObjectListT<I, E>;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [15.8.3] `extended-atomic` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct FailT {
|
|
using MemoryOrder = type::MemoryOrder;
|
|
using WrapperTrait = std::true_type;
|
|
MemoryOrder v;
|
|
};
|
|
|
|
// V5.2: [10.5.1] `filter` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct FilterT {
|
|
using ThreadNum = E;
|
|
using WrapperTrait = std::true_type;
|
|
ThreadNum v;
|
|
};
|
|
|
|
// V5.2: [12.3] `final` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct FinalT {
|
|
using Finalize = E;
|
|
using WrapperTrait = std::true_type;
|
|
Finalize v;
|
|
};
|
|
|
|
// V5.2: [5.4.4] `firstprivate` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct FirstprivateT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [5.9.2] `from` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct FromT {
|
|
using LocatorList = ObjectListT<I, E>;
|
|
using Expectation = type::MotionExpectation;
|
|
using Iterator = type::IteratorT<T, I, E>;
|
|
// See note at the definition of the MapperT type.
|
|
using Mappers = ListT<type::MapperT<I, E>>; // Not a spec name
|
|
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(Expectation), OPT(Mappers), OPT(Iterator), LocatorList> t;
|
|
};
|
|
|
|
// V5.2: [9.2.1] `full` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct FullT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [12.6.1] `grainsize` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct GrainsizeT {
|
|
using Prescriptiveness = type::Prescriptiveness;
|
|
using GrainSize = E;
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(Prescriptiveness), GrainSize> t;
|
|
};
|
|
|
|
// V5.2: [5.4.9] `has_device_addr` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct HasDeviceAddrT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [15.1.2] `hint` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct HintT {
|
|
using HintExpr = E;
|
|
using WrapperTrait = std::true_type;
|
|
HintExpr v;
|
|
};
|
|
|
|
// V5.2: [8.3.1] Assumption clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct HoldsT {
|
|
using WrapperTrait = std::true_type;
|
|
E v; // No argument name in spec 5.2
|
|
};
|
|
|
|
// V5.2: [3.4] `if` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct IfT {
|
|
using DirectiveNameModifier = type::DirectiveName;
|
|
using IfExpression = E;
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(DirectiveNameModifier), IfExpression> t;
|
|
};
|
|
|
|
// V5.2: [7.7.1] `branch` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct InbranchT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [5.6.1] `exclusive` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct InclusiveT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [7.8.3] `indirect` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct IndirectT {
|
|
using InvokedByFptr = E;
|
|
using WrapperTrait = std::true_type;
|
|
OPT(InvokedByFptr) v;
|
|
};
|
|
|
|
// V5.2: [14.1.2] `init` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct InitT {
|
|
using ForeignRuntimeId = E;
|
|
using InteropVar = ObjectT<I, E>;
|
|
using InteropPreference = ListT<ForeignRuntimeId>;
|
|
ENUM(InteropType, Target, Targetsync); // Repeatable
|
|
using InteropTypes = ListT<InteropType>; // Not a spec name
|
|
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(InteropPreference), InteropTypes, InteropVar> t;
|
|
};
|
|
|
|
// V5.2: [5.5.4] `initializer` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct InitializerT {
|
|
using InitializerExpr = E;
|
|
using WrapperTrait = std::true_type;
|
|
InitializerExpr v;
|
|
};
|
|
|
|
// V5.2: [5.5.10] `in_reduction` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct InReductionT {
|
|
using List = ObjectListT<I, E>;
|
|
// See note at the definition of the ReductionIdentifierT type.
|
|
// The name ReductionIdentifiers is not a spec name.
|
|
using ReductionIdentifiers = ListT<type::ReductionIdentifierT<I, E>>;
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<ReductionIdentifiers, List> t;
|
|
};
|
|
|
|
// V5.2: [5.4.7] `is_device_ptr` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct IsDevicePtrT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [5.4.5] `lastprivate` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct LastprivateT {
|
|
using List = ObjectListT<I, E>;
|
|
ENUM(LastprivateModifier, Conditional);
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(LastprivateModifier), List> t;
|
|
};
|
|
|
|
// V5.2: [5.4.6] `linear` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct LinearT {
|
|
// std::get<type> won't work here due to duplicate types in the tuple.
|
|
using List = ObjectListT<I, E>;
|
|
// StepSimpleModifier is same as StepComplexModifier.
|
|
using StepComplexModifier = E;
|
|
ENUM(LinearModifier, Ref, Val, Uval);
|
|
|
|
using TupleTrait = std::true_type;
|
|
// Step == nullopt means 1.
|
|
std::tuple<OPT(StepComplexModifier), OPT(LinearModifier), List> t;
|
|
};
|
|
|
|
// V5.2: [5.8.5] `link` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct LinkT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [5.8.3] `map` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct MapT {
|
|
using LocatorList = ObjectListT<I, E>;
|
|
ENUM(MapType, To, From, Tofrom, Storage);
|
|
ENUM(MapTypeModifier, Always, Close, Delete, Present, Self, OmpxHold);
|
|
ENUM(RefModifier, RefPtee, RefPtr, RefPtrPtee);
|
|
// See note at the definition of the MapperT type.
|
|
using Mappers = ListT<type::MapperT<I, E>>; // Not a spec name
|
|
using Iterator = type::IteratorT<T, I, E>;
|
|
using MapTypeModifiers = ListT<MapTypeModifier>; // Not a spec name
|
|
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(MapType), OPT(MapTypeModifiers), OPT(RefModifier),
|
|
OPT(Mappers), OPT(Iterator), LocatorList>
|
|
t;
|
|
};
|
|
|
|
// V5.2: [7.5.1] `match` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct MatchT {
|
|
using IncompleteTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [12.2] `mergeable` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct MergeableT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.5.2] `message` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct MessageT {
|
|
using MsgString = E;
|
|
using WrapperTrait = std::true_type;
|
|
MsgString v;
|
|
};
|
|
|
|
// V5.2: [7.6.2] `nocontext` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NocontextT {
|
|
using DoNotUpdateContext = E;
|
|
using WrapperTrait = std::true_type;
|
|
DoNotUpdateContext v;
|
|
};
|
|
|
|
// V5.2: [15.7] `nowait` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NogroupT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [10.4.1] `nontemporal` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NontemporalT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [8.3.1] `assumption` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct NoOpenmpT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.3.1] `assumption` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct NoOpenmpRoutinesT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V6.0: [10.6.1] `assumption` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct NoOpenmpConstructsT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.3.1] `assumption` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct NoParallelismT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [7.7.1] `branch` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct NotinbranchT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [7.6.1] `novariants` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NovariantsT {
|
|
using DoNotUseVariant = E;
|
|
using WrapperTrait = std::true_type;
|
|
DoNotUseVariant v;
|
|
};
|
|
|
|
// V5.2: [15.6] `nowait` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NowaitT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [12.6.2] `num_tasks` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NumTasksT {
|
|
using Prescriptiveness = type::Prescriptiveness;
|
|
using NumTasks = E;
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(Prescriptiveness), NumTasks> t;
|
|
};
|
|
|
|
// V5.2: [10.2.1] `num_teams` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NumTeamsT {
|
|
using LowerBound = E;
|
|
using UpperBound = E;
|
|
|
|
// The name Range is not a spec name.
|
|
struct Range {
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(LowerBound), UpperBound> t;
|
|
};
|
|
|
|
// The name List is not a spec name. The list is an extension to allow
|
|
// specifying a grid with connection with the ompx_bare clause.
|
|
using List = ListT<Range>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [10.1.2] `num_threads` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct NumThreadsT {
|
|
using Nthreads = E;
|
|
using WrapperTrait = std::true_type;
|
|
Nthreads v;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
struct OmpxAttributeT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
struct OmpxBareT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
struct OmpxDynCgroupMemT {
|
|
using WrapperTrait = std::true_type;
|
|
E v;
|
|
};
|
|
|
|
// V5.2: [10.3] `order` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct OrderT {
|
|
ENUM(OrderModifier, Reproducible, Unconstrained);
|
|
ENUM(Ordering, Concurrent);
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(OrderModifier), Ordering> t;
|
|
};
|
|
|
|
// V5.2: [4.4.4] `ordered` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct OrderedT {
|
|
using N = E;
|
|
using WrapperTrait = std::true_type;
|
|
OPT(N) v;
|
|
};
|
|
|
|
// V5.2: [7.4.2] `otherwise` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct OtherwiseT {
|
|
using IncompleteTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [9.2.2] `partial` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct PartialT {
|
|
using UnrollFactor = E;
|
|
using WrapperTrait = std::true_type;
|
|
OPT(UnrollFactor) v;
|
|
};
|
|
|
|
// V6.0: `permutation` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct PermutationT {
|
|
using ArgList = ListT<E>;
|
|
using WrapperTrait = std::true_type;
|
|
ArgList v;
|
|
};
|
|
|
|
// V5.2: [12.4] `priority` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct PriorityT {
|
|
using PriorityValue = E;
|
|
using WrapperTrait = std::true_type;
|
|
PriorityValue v;
|
|
};
|
|
|
|
// V5.2: [5.4.3] `private` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct PrivateT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [10.1.4] `proc_bind` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct ProcBindT {
|
|
ENUM(AffinityPolicy, Close, Master, Spread, Primary);
|
|
using WrapperTrait = std::true_type;
|
|
AffinityPolicy v;
|
|
};
|
|
|
|
// V5.2: [15.8.2] Atomic clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct ReadT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [5.5.8] `reduction` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct ReductionT {
|
|
using List = ObjectListT<I, E>;
|
|
// See note at the definition of the ReductionIdentifierT type.
|
|
// The name ReductionIdentifiers is not a spec name.
|
|
using ReductionIdentifiers = ListT<type::ReductionIdentifierT<I, E>>;
|
|
ENUM(ReductionModifier, Default, Inscan, Task);
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(ReductionModifier), ReductionIdentifiers, List> t;
|
|
};
|
|
|
|
// V5.2: [15.8.1] `memory-order` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct RelaxedT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [15.8.1] `memory-order` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct ReleaseT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.2.1] `requirement` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct ReverseOffloadT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [10.4.2] `safelen` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct SafelenT {
|
|
using Length = E;
|
|
using WrapperTrait = std::true_type;
|
|
Length v;
|
|
};
|
|
|
|
// V5.2: [11.5.3] `schedule` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct ScheduleT {
|
|
ENUM(Kind, Static, Dynamic, Guided, Auto, Runtime);
|
|
using ChunkSize = E;
|
|
ENUM(OrderingModifier, Monotonic, Nonmonotonic);
|
|
ENUM(ChunkModifier, Simd);
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<Kind, OPT(OrderingModifier), OPT(ChunkModifier), OPT(ChunkSize)> t;
|
|
};
|
|
|
|
// V5.2: [15.8.1] Memory-order clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct SeqCstT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.5.1] `severity` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct SeverityT {
|
|
ENUM(SevLevel, Fatal, Warning);
|
|
using WrapperTrait = std::true_type;
|
|
SevLevel v;
|
|
};
|
|
|
|
// V5.2: [5.4.2] `shared` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct SharedT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [15.10.3] `parallelization-level` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct SimdT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [10.4.3] `simdlen` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct SimdlenT {
|
|
using Length = E;
|
|
using WrapperTrait = std::true_type;
|
|
Length v;
|
|
};
|
|
|
|
// V5.2: [9.1.1] `sizes` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct SizesT {
|
|
using SizeList = ListT<E>;
|
|
using WrapperTrait = std::true_type;
|
|
SizeList v;
|
|
};
|
|
|
|
// V5.2: [5.5.9] `task_reduction` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct TaskReductionT {
|
|
using List = ObjectListT<I, E>;
|
|
// See note at the definition of the ReductionIdentifierT type.
|
|
// The name ReductionIdentifiers is not a spec name.
|
|
using ReductionIdentifiers = ListT<type::ReductionIdentifierT<I, E>>;
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<ReductionIdentifiers, List> t;
|
|
};
|
|
|
|
// V5.2: [13.3] `thread_limit` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct ThreadLimitT {
|
|
using Threadlim = E;
|
|
using WrapperTrait = std::true_type;
|
|
Threadlim v;
|
|
};
|
|
|
|
// V5.2: [15.10.3] `parallelization-level` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct ThreadsT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [5.9.1] `to` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct ToT {
|
|
using LocatorList = ObjectListT<I, E>;
|
|
using Expectation = type::MotionExpectation;
|
|
// See note at the definition of the MapperT type.
|
|
using Mappers = ListT<type::MapperT<I, E>>; // Not a spec name
|
|
using Iterator = type::IteratorT<T, I, E>;
|
|
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(Expectation), OPT(Mappers), OPT(Iterator), LocatorList> t;
|
|
};
|
|
|
|
// V5.2: [8.2.1] `requirement` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct UnifiedAddressT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [8.2.1] `requirement` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct UnifiedSharedMemoryT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
struct SelfMapsT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [5.10] `uniform` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct UniformT {
|
|
using ParameterList = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
ParameterList v;
|
|
};
|
|
|
|
template <typename T, typename I, typename E> //
|
|
struct UnknownT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [12.1] `untied` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct UntiedT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// Both of the following
|
|
// V5.2: [15.8.2] `atomic` clauses
|
|
// V5.2: [15.9.3] `update` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct UpdateT {
|
|
using DependenceType = tomp::type::DependenceType;
|
|
using WrapperTrait = std::true_type;
|
|
OPT(DependenceType) v;
|
|
};
|
|
|
|
// V5.2: [14.1.3] `use` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct UseT {
|
|
using InteropVar = ObjectT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
InteropVar v;
|
|
};
|
|
|
|
// V5.2: [5.4.10] `use_device_addr` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct UseDeviceAddrT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [5.4.8] `use_device_ptr` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct UseDevicePtrT {
|
|
using List = ObjectListT<I, E>;
|
|
using WrapperTrait = std::true_type;
|
|
List v;
|
|
};
|
|
|
|
// V5.2: [6.8] `uses_allocators` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct UsesAllocatorsT {
|
|
using MemSpace = E;
|
|
using TraitsArray = ObjectT<I, E>;
|
|
using Allocator = E;
|
|
struct AllocatorSpec { // Not a spec name
|
|
using TupleTrait = std::true_type;
|
|
std::tuple<OPT(MemSpace), OPT(TraitsArray), Allocator> t;
|
|
};
|
|
using Allocators = ListT<AllocatorSpec>; // Not a spec name
|
|
using WrapperTrait = std::true_type;
|
|
Allocators v;
|
|
};
|
|
|
|
// V5.2: [15.8.3] `extended-atomic` clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct WeakT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [7.4.1] `when` clause
|
|
template <typename T, typename I, typename E> //
|
|
struct WhenT {
|
|
using IncompleteTrait = std::true_type;
|
|
};
|
|
|
|
// V5.2: [15.8.2] Atomic clauses
|
|
template <typename T, typename I, typename E> //
|
|
struct WriteT {
|
|
using EmptyTrait = std::true_type;
|
|
};
|
|
|
|
// ---
|
|
|
|
template <typename T, typename I, typename E>
|
|
using ExtensionClausesT =
|
|
std::variant<OmpxAttributeT<T, I, E>, OmpxBareT<T, I, E>,
|
|
OmpxDynCgroupMemT<T, I, E>>;
|
|
|
|
template <typename T, typename I, typename E>
|
|
using EmptyClausesT = std::variant<
|
|
AcqRelT<T, I, E>, AcquireT<T, I, E>, CaptureT<T, I, E>, CompareT<T, I, E>,
|
|
DynamicAllocatorsT<T, I, E>, FullT<T, I, E>, InbranchT<T, I, E>,
|
|
MergeableT<T, I, E>, NogroupT<T, I, E>, NoOpenmpRoutinesT<T, I, E>,
|
|
NoOpenmpT<T, I, E>, NoParallelismT<T, I, E>, NotinbranchT<T, I, E>,
|
|
NowaitT<T, I, E>, ReadT<T, I, E>, RelaxedT<T, I, E>, ReleaseT<T, I, E>,
|
|
ReverseOffloadT<T, I, E>, SeqCstT<T, I, E>, SimdT<T, I, E>,
|
|
ThreadsT<T, I, E>, UnifiedAddressT<T, I, E>, UnifiedSharedMemoryT<T, I, E>,
|
|
UnknownT<T, I, E>, UntiedT<T, I, E>, UseT<T, I, E>, WeakT<T, I, E>,
|
|
WriteT<T, I, E>, NoOpenmpConstructsT<T, I, E>, SelfMapsT<T, I, E>>;
|
|
|
|
template <typename T, typename I, typename E>
|
|
using IncompleteClausesT =
|
|
std::variant<AdjustArgsT<T, I, E>, AppendArgsT<T, I, E>, MatchT<T, I, E>,
|
|
OtherwiseT<T, I, E>, WhenT<T, I, E>>;
|
|
|
|
template <typename T, typename I, typename E>
|
|
using TupleClausesT =
|
|
std::variant<AffinityT<T, I, E>, AlignedT<T, I, E>, AllocateT<T, I, E>,
|
|
DefaultmapT<T, I, E>, DeviceT<T, I, E>, DistScheduleT<T, I, E>,
|
|
DoacrossT<T, I, E>, FromT<T, I, E>, GrainsizeT<T, I, E>,
|
|
IfT<T, I, E>, InitT<T, I, E>, InReductionT<T, I, E>,
|
|
LastprivateT<T, I, E>, LinearT<T, I, E>, MapT<T, I, E>,
|
|
NumTasksT<T, I, E>, OrderT<T, I, E>, ReductionT<T, I, E>,
|
|
ScheduleT<T, I, E>, TaskReductionT<T, I, E>, ToT<T, I, E>>;
|
|
|
|
template <typename T, typename I, typename E>
|
|
using UnionClausesT = std::variant<DependT<T, I, E>>;
|
|
|
|
template <typename T, typename I, typename E>
|
|
using WrapperClausesT = std::variant<
|
|
AbsentT<T, I, E>, AlignT<T, I, E>, AllocatorT<T, I, E>,
|
|
AtomicDefaultMemOrderT<T, I, E>, AtT<T, I, E>, BindT<T, I, E>,
|
|
CollapseT<T, I, E>, ContainsT<T, I, E>, CopyinT<T, I, E>,
|
|
CopyprivateT<T, I, E>, DefaultT<T, I, E>, DestroyT<T, I, E>,
|
|
DetachT<T, I, E>, DeviceTypeT<T, I, E>, EnterT<T, I, E>,
|
|
ExclusiveT<T, I, E>, FailT<T, I, E>, FilterT<T, I, E>, FinalT<T, I, E>,
|
|
FirstprivateT<T, I, E>, HasDeviceAddrT<T, I, E>, HintT<T, I, E>,
|
|
HoldsT<T, I, E>, InclusiveT<T, I, E>, IndirectT<T, I, E>,
|
|
InitializerT<T, I, E>, IsDevicePtrT<T, I, E>, LinkT<T, I, E>,
|
|
MessageT<T, I, E>, NocontextT<T, I, E>, NontemporalT<T, I, E>,
|
|
NovariantsT<T, I, E>, NumTeamsT<T, I, E>, NumThreadsT<T, I, E>,
|
|
OrderedT<T, I, E>, PartialT<T, I, E>, PriorityT<T, I, E>, PrivateT<T, I, E>,
|
|
ProcBindT<T, I, E>, SafelenT<T, I, E>, SeverityT<T, I, E>, SharedT<T, I, E>,
|
|
SimdlenT<T, I, E>, SizesT<T, I, E>, PermutationT<T, I, E>,
|
|
ThreadLimitT<T, I, E>, UniformT<T, I, E>, UpdateT<T, I, E>,
|
|
UseDeviceAddrT<T, I, E>, UseDevicePtrT<T, I, E>, UsesAllocatorsT<T, I, E>>;
|
|
|
|
template <typename T, typename I, typename E>
|
|
using UnionOfAllClausesT = typename type::Union< //
|
|
EmptyClausesT<T, I, E>, //
|
|
ExtensionClausesT<T, I, E>, //
|
|
IncompleteClausesT<T, I, E>, //
|
|
TupleClausesT<T, I, E>, //
|
|
UnionClausesT<T, I, E>, //
|
|
WrapperClausesT<T, I, E> //
|
|
>::type;
|
|
} // namespace clause
|
|
|
|
using type::operator==;
|
|
|
|
// The variant wrapper that encapsulates all possible specific clauses.
|
|
// The `Extras` arguments are additional types representing local extensions
|
|
// to the clause set, e.g.
|
|
//
|
|
// using Clause = ClauseT<Type, Id, Expr,
|
|
// MyClause1, MyClause2>;
|
|
//
|
|
// The member Clause::u will be a variant containing all specific clauses
|
|
// defined above, plus MyClause1 and MyClause2.
|
|
//
|
|
// Note: Any derived class must be constructible from the base class
|
|
// ClauseT<...>.
|
|
template <typename TypeType, typename IdType, typename ExprType,
|
|
typename... Extras>
|
|
struct ClauseT {
|
|
using TypeTy = TypeType;
|
|
using IdTy = IdType;
|
|
using ExprTy = ExprType;
|
|
|
|
// Type of "self" to specify this type given a derived class type.
|
|
using BaseT = ClauseT<TypeType, IdType, ExprType, Extras...>;
|
|
|
|
using VariantTy = typename type::Union<
|
|
clause::UnionOfAllClausesT<TypeType, IdType, ExprType>,
|
|
std::variant<Extras...>>::type;
|
|
|
|
llvm::omp::Clause id; // The numeric id of the clause
|
|
using UnionTrait = std::true_type;
|
|
VariantTy u;
|
|
};
|
|
|
|
template <typename ClauseType> struct DirectiveWithClauses {
|
|
llvm::omp::Directive id = llvm::omp::Directive::OMPD_unknown;
|
|
tomp::type::ListT<ClauseType> clauses;
|
|
};
|
|
|
|
} // namespace tomp
|
|
|
|
#undef OPT
|
|
#undef ENUM
|
|
|
|
#endif // LLVM_FRONTEND_OPENMP_CLAUSET_H
|