//===- 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>; // using TupleTrait = std::true_type; // std::tuple, 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 #include #include #include #include #include #include #define ENUM(Name, ...) enum class Name { __VA_ARGS__ } #define OPT(x) std::optional // 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 struct is_variant { static constexpr bool value = false; }; template struct is_variant> { static constexpr bool value = true; }; template constexpr bool is_variant_v = is_variant::value; // Helper utility to create a type which is a union of two given variants. template struct UnionOfTwo; template struct UnionOfTwo, std::variant> { using type = std::variant; }; } // namespace detail namespace tomp { namespace type { // Helper utility to create a type which is a union of an arbitrary number // of variants. template struct Union; template <> struct Union<> { // Legal to define, illegal to instantiate. using type = std::variant<>; }; template struct Union { static_assert(detail::is_variant_v); using type = typename detail::UnionOfTwo::type>::type; }; template using ListT = llvm::SmallVector; // 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 struct ObjectT; // By default, object equality is only determined by its identity. template bool operator==(const ObjectT &o1, const ObjectT &o2) { return o1.id() == o2.id(); } template using ObjectListT = ListT>; using DirectiveName = llvm::omp::Directive; template // struct DefinedOperatorT { struct DefinedOpName { using WrapperTrait = std::true_type; ObjectT 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 u; }; // V5.2: [3.2.6] `iterator` modifier template // struct RangeT { // range-specification: begin : end[: step] using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [3.2.6] `iterator` modifier template // struct IteratorSpecifierT { // iterators-specifier: [ iterator-type ] identifier = range-specification using TupleTrait = std::true_type; std::tuple, RangeT> 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 // struct MapperT { using MapperIdentifier = ObjectT; 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); // V5.2: [15.9.1] `task-dependence-type` modifier ENUM(TaskDependenceType, In, Out, Inout, Mutexinoutset, Inoutset, Depobj); template // struct LoopIterationT { struct Distance { using TupleTrait = std::true_type; std::tuple, E> t; }; using TupleTrait = std::true_type; std::tuple, OPT(Distance)> t; }; template // struct ProcedureDesignatorT { using WrapperTrait = std::true_type; ObjectT 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 // struct ReductionIdentifierT { using UnionTrait = std::true_type; std::variant, ProcedureDesignatorT> u; }; template // using IteratorT = ListT>; template std::enable_if_t operator==(const T &a, const T &b) { return true; } template std::enable_if_t operator==(const T &a, const T &b) { return true; } template std::enable_if_t operator==(const T &a, const T &b) { return a.v == b.v; } template std::enable_if_t operator==(const T &a, const T &b) { return a.t == b.t; } template std::enable_if_t operator==(const T &a, const T &b) { return a.u == b.u; } } // namespace type template using ListT = type::ListT; template using ObjectT = type::ObjectT; template using ObjectListT = type::ObjectListT; template using IteratorT = type::IteratorT; template < typename ContainerTy, typename FunctionTy, typename ElemTy = typename llvm::remove_cvref_t::value_type, typename ResultTy = std::invoke_result_t> ListT makeList(ContainerTy &&container, FunctionTy &&func) { ListT v; llvm::transform(container, std::back_inserter(v), func); return v; } namespace clause { using type::operator==; // V5.2: [8.3.1] `assumption` clauses template // struct AbsentT { using List = ListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [15.8.1] `memory-order` clauses template // struct AcqRelT { using EmptyTrait = std::true_type; }; // V5.2: [15.8.1] `memory-order` clauses template // struct AcquireT { using EmptyTrait = std::true_type; }; // V5.2: [7.5.2] `adjust_args` clause template // struct AdjustArgsT { using IncompleteTrait = std::true_type; }; // V5.2: [12.5.1] `affinity` clause template // struct AffinityT { using Iterator = type::IteratorT; using LocatorList = ObjectListT; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [6.3] `align` clause template // struct AlignT { using Alignment = E; using WrapperTrait = std::true_type; Alignment v; }; // V5.2: [5.11] `aligned` clause template // struct AlignedT { using Alignment = E; using List = ObjectListT; using TupleTrait = std::true_type; std::tuple t; }; template // struct AllocatorT; // V5.2: [6.6] `allocate` clause template // struct AllocateT { using AllocatorSimpleModifier = E; using AllocatorComplexModifier = AllocatorT; using AlignModifier = AlignT; using List = ObjectListT; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [6.4] `allocator` clause template // struct AllocatorT { using Allocator = E; using WrapperTrait = std::true_type; Allocator v; }; // V5.2: [7.5.3] `append_args` clause template // struct AppendArgsT { using IncompleteTrait = std::true_type; }; // V5.2: [8.1] `at` clause template // struct AtT { ENUM(ActionTime, Compilation, Execution); using WrapperTrait = std::true_type; ActionTime v; }; // V5.2: [8.2.1] `requirement` clauses template // 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 // struct BindT { ENUM(Binding, Teams, Parallel, Thread); using WrapperTrait = std::true_type; Binding v; }; // V5.2: [15.8.3] `extended-atomic` clauses template // struct CaptureT { using EmptyTrait = std::true_type; }; // V5.2: [4.4.3] `collapse` clause template // struct CollapseT { using N = E; using WrapperTrait = std::true_type; N v; }; // V5.2: [15.8.3] `extended-atomic` clauses template // struct CompareT { using EmptyTrait = std::true_type; }; // V5.2: [8.3.1] `assumption` clauses template // struct ContainsT { using List = ListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.7.1] `copyin` clause template // struct CopyinT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.7.2] `copyprivate` clause template // struct CopyprivateT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.4.1] `default` clause template // struct DefaultT { ENUM(DataSharingAttribute, Firstprivate, None, Private, Shared); using WrapperTrait = std::true_type; DataSharingAttribute v; }; // V5.2: [5.8.7] `defaultmap` clause template // struct DefaultmapT { ENUM(ImplicitBehavior, Alloc, To, From, Tofrom, Firstprivate, None, Default, Present); ENUM(VariableCategory, Scalar, Aggregate, Pointer, Allocatable); using TupleTrait = std::true_type; std::tuple t; }; template // struct DoacrossT; // V5.2: [15.9.5] `depend` clause template // struct DependT { using Iterator = type::IteratorT; using LocatorList = ObjectListT; using TaskDependenceType = tomp::type::TaskDependenceType; struct WithLocators { // Modern form using TupleTrait = std::true_type; // Empty LocatorList means "omp_all_memory". std::tuple t; }; using Doacross = DoacrossT; using UnionTrait = std::true_type; std::variant u; // Doacross form is legacy }; // V5.2: [3.5] `destroy` clause template // struct DestroyT { using DestroyVar = ObjectT; using WrapperTrait = std::true_type; // DestroyVar can be ommitted in "depobj destroy". OPT(DestroyVar) v; }; // V5.2: [12.5.2] `detach` clause template // struct DetachT { using EventHandle = ObjectT; using WrapperTrait = std::true_type; EventHandle v; }; // V5.2: [13.2] `device` clause template // struct DeviceT { using DeviceDescription = E; ENUM(DeviceModifier, Ancestor, DeviceNum); using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [13.1] `device_type` clause template // struct DeviceTypeT { ENUM(DeviceTypeDescription, Any, Host, Nohost); using WrapperTrait = std::true_type; DeviceTypeDescription v; }; // V5.2: [11.6.1] `dist_schedule` clause template // struct DistScheduleT { ENUM(Kind, Static); using ChunkSize = E; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [15.9.6] `doacross` clause template // struct DoacrossT { using Vector = ListT>; ENUM(DependenceType, Source, Sink); using TupleTrait = std::true_type; // Empty Vector means "omp_cur_iteration" std::tuple t; }; // V5.2: [8.2.1] `requirement` clauses template // struct DynamicAllocatorsT { using EmptyTrait = std::true_type; }; // V5.2: [5.8.4] `enter` clause template // struct EnterT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.6.2] `exclusive` clause template // struct ExclusiveT { using WrapperTrait = std::true_type; using List = ObjectListT; List v; }; // V5.2: [15.8.3] `extended-atomic` clauses template // struct FailT { using MemoryOrder = type::MemoryOrder; using WrapperTrait = std::true_type; MemoryOrder v; }; // V5.2: [10.5.1] `filter` clause template // struct FilterT { using ThreadNum = E; using WrapperTrait = std::true_type; ThreadNum v; }; // V5.2: [12.3] `final` clause template // struct FinalT { using Finalize = E; using WrapperTrait = std::true_type; Finalize v; }; // V5.2: [5.4.4] `firstprivate` clause template // struct FirstprivateT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.9.2] `from` clause template // struct FromT { using LocatorList = ObjectListT; using Expectation = type::MotionExpectation; using Iterator = type::IteratorT; // See note at the definition of the MapperT type. using Mappers = ListT>; // Not a spec name using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [9.2.1] `full` clause template // struct FullT { using EmptyTrait = std::true_type; }; // V5.2: [12.6.1] `grainsize` clause template // struct GrainsizeT { ENUM(Prescriptiveness, Strict); using GrainSize = E; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [5.4.9] `has_device_addr` clause template // struct HasDeviceAddrT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [15.1.2] `hint` clause template // struct HintT { using HintExpr = E; using WrapperTrait = std::true_type; HintExpr v; }; // V5.2: [8.3.1] Assumption clauses template // struct HoldsT { using WrapperTrait = std::true_type; E v; // No argument name in spec 5.2 }; // V5.2: [3.4] `if` clause template // struct IfT { using DirectiveNameModifier = type::DirectiveName; using IfExpression = E; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [7.7.1] `branch` clauses template // struct InbranchT { using EmptyTrait = std::true_type; }; // V5.2: [5.6.1] `exclusive` clause template // struct InclusiveT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [7.8.3] `indirect` clause template // struct IndirectT { using InvokedByFptr = E; using WrapperTrait = std::true_type; InvokedByFptr v; }; // V5.2: [14.1.2] `init` clause template // struct InitT { using ForeignRuntimeId = E; using InteropVar = ObjectT; using InteropPreference = ListT; ENUM(InteropType, Target, Targetsync); // Repeatable using InteropTypes = ListT; // Not a spec name using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [5.5.4] `initializer` clause template // struct InitializerT { using InitializerExpr = E; using WrapperTrait = std::true_type; InitializerExpr v; }; // V5.2: [5.5.10] `in_reduction` clause template // struct InReductionT { using List = ObjectListT; // See note at the definition of the ReductionIdentifierT type. // The name ReductionIdentifiers is not a spec name. using ReductionIdentifiers = ListT>; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [5.4.7] `is_device_ptr` clause template // struct IsDevicePtrT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.4.5] `lastprivate` clause template // struct LastprivateT { using List = ObjectListT; ENUM(LastprivateModifier, Conditional); using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [5.4.6] `linear` clause template // struct LinearT { // std::get won't work here due to duplicate types in the tuple. using List = ObjectListT; using StepSimpleModifier = E; using StepComplexModifier = E; ENUM(LinearModifier, Ref, Val, Uval); using TupleTrait = std::true_type; // Step == nullopt means 1. std::tuple t; }; // V5.2: [5.8.5] `link` clause template // struct LinkT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.8.3] `map` clause template // struct MapT { using LocatorList = ObjectListT; ENUM(MapType, To, From, Tofrom, Alloc, Release, Delete); ENUM(MapTypeModifier, Always, Close, Present, OmpxHold); // See note at the definition of the MapperT type. using Mappers = ListT>; // Not a spec name using Iterator = type::IteratorT; using MapTypeModifiers = ListT; // Not a spec name using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [7.5.1] `match` clause template // struct MatchT { using IncompleteTrait = std::true_type; }; // V5.2: [12.2] `mergeable` clause template // struct MergeableT { using EmptyTrait = std::true_type; }; // V5.2: [8.5.2] `message` clause template // struct MessageT { using MsgString = E; using WrapperTrait = std::true_type; MsgString v; }; // V5.2: [7.6.2] `nocontext` clause template // struct NocontextT { using DoNotUpdateContext = E; using WrapperTrait = std::true_type; DoNotUpdateContext v; }; // V5.2: [15.7] `nowait` clause template // struct NogroupT { using EmptyTrait = std::true_type; }; // V5.2: [10.4.1] `nontemporal` clause template // struct NontemporalT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [8.3.1] `assumption` clauses template // struct NoOpenmpT { using EmptyTrait = std::true_type; }; // V5.2: [8.3.1] `assumption` clauses template // struct NoOpenmpRoutinesT { using EmptyTrait = std::true_type; }; // V5.2: [8.3.1] `assumption` clauses template // struct NoParallelismT { using EmptyTrait = std::true_type; }; // V5.2: [7.7.1] `branch` clauses template // struct NotinbranchT { using EmptyTrait = std::true_type; }; // V5.2: [7.6.1] `novariants` clause template // struct NovariantsT { using DoNotUseVariant = E; using WrapperTrait = std::true_type; DoNotUseVariant v; }; // V5.2: [15.6] `nowait` clause template // struct NowaitT { using EmptyTrait = std::true_type; }; // V5.2: [12.6.2] `num_tasks` clause template // struct NumTasksT { using NumTasks = E; ENUM(Prescriptiveness, Strict); using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [10.2.1] `num_teams` clause template // struct NumTeamsT { using TupleTrait = std::true_type; using LowerBound = E; using UpperBound = E; std::tuple t; }; // V5.2: [10.1.2] `num_threads` clause template // struct NumThreadsT { using Nthreads = E; using WrapperTrait = std::true_type; Nthreads v; }; template // struct OmpxAttributeT { using EmptyTrait = std::true_type; }; template // struct OmpxBareT { using EmptyTrait = std::true_type; }; template // struct OmpxDynCgroupMemT { using WrapperTrait = std::true_type; E v; }; // V5.2: [10.3] `order` clause template // struct OrderT { ENUM(OrderModifier, Reproducible, Unconstrained); ENUM(Ordering, Concurrent); using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [4.4.4] `ordered` clause template // struct OrderedT { using N = E; using WrapperTrait = std::true_type; OPT(N) v; }; // V5.2: [7.4.2] `otherwise` clause template // struct OtherwiseT { using IncompleteTrait = std::true_type; }; // V5.2: [9.2.2] `partial` clause template // struct PartialT { using UnrollFactor = E; using WrapperTrait = std::true_type; OPT(UnrollFactor) v; }; // V5.2: [12.4] `priority` clause template // struct PriorityT { using PriorityValue = E; using WrapperTrait = std::true_type; PriorityValue v; }; // V5.2: [5.4.3] `private` clause template // struct PrivateT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [10.1.4] `proc_bind` clause template // struct ProcBindT { ENUM(AffinityPolicy, Close, Master, Spread, Primary); using WrapperTrait = std::true_type; AffinityPolicy v; }; // V5.2: [15.8.2] Atomic clauses template // struct ReadT { using EmptyTrait = std::true_type; }; // V5.2: [5.5.8] `reduction` clause template // struct ReductionT { using List = ObjectListT; // See note at the definition of the ReductionIdentifierT type. // The name ReductionIdentifiers is not a spec name. using ReductionIdentifiers = ListT>; ENUM(ReductionModifier, Default, Inscan, Task); using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [15.8.1] `memory-order` clauses template // struct RelaxedT { using EmptyTrait = std::true_type; }; // V5.2: [15.8.1] `memory-order` clauses template // struct ReleaseT { using EmptyTrait = std::true_type; }; // V5.2: [8.2.1] `requirement` clauses template // struct ReverseOffloadT { using EmptyTrait = std::true_type; }; // V5.2: [10.4.2] `safelen` clause template // struct SafelenT { using Length = E; using WrapperTrait = std::true_type; Length v; }; // V5.2: [11.5.3] `schedule` clause template // 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 t; }; // V5.2: [15.8.1] Memory-order clauses template // struct SeqCstT { using EmptyTrait = std::true_type; }; // V5.2: [8.5.1] `severity` clause template // struct SeverityT { ENUM(SevLevel, Fatal, Warning); using WrapperTrait = std::true_type; SevLevel v; }; // V5.2: [5.4.2] `shared` clause template // struct SharedT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [15.10.3] `parallelization-level` clauses template // struct SimdT { using EmptyTrait = std::true_type; }; // V5.2: [10.4.3] `simdlen` clause template // struct SimdlenT { using Length = E; using WrapperTrait = std::true_type; Length v; }; // V5.2: [9.1.1] `sizes` clause template // struct SizesT { using SizeList = ListT; using WrapperTrait = std::true_type; SizeList v; }; // V5.2: [5.5.9] `task_reduction` clause template // struct TaskReductionT { using List = ObjectListT; // See note at the definition of the ReductionIdentifierT type. // The name ReductionIdentifiers is not a spec name. using ReductionIdentifiers = ListT>; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [13.3] `thread_limit` clause template // struct ThreadLimitT { using Threadlim = E; using WrapperTrait = std::true_type; Threadlim v; }; // V5.2: [15.10.3] `parallelization-level` clauses template // struct ThreadsT { using EmptyTrait = std::true_type; }; // V5.2: [5.9.1] `to` clause template // struct ToT { using LocatorList = ObjectListT; using Expectation = type::MotionExpectation; // See note at the definition of the MapperT type. using Mappers = ListT>; // Not a spec name using Iterator = type::IteratorT; using TupleTrait = std::true_type; std::tuple t; }; // V5.2: [8.2.1] `requirement` clauses template // struct UnifiedAddressT { using EmptyTrait = std::true_type; }; // V5.2: [8.2.1] `requirement` clauses template // struct UnifiedSharedMemoryT { using EmptyTrait = std::true_type; }; // V5.2: [5.10] `uniform` clause template // struct UniformT { using ParameterList = ObjectListT; using WrapperTrait = std::true_type; ParameterList v; }; template // struct UnknownT { using EmptyTrait = std::true_type; }; // V5.2: [12.1] `untied` clause template // 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 // struct UpdateT { using TaskDependenceType = tomp::type::TaskDependenceType; using WrapperTrait = std::true_type; OPT(TaskDependenceType) v; }; // V5.2: [14.1.3] `use` clause template // struct UseT { using InteropVar = ObjectT; using WrapperTrait = std::true_type; InteropVar v; }; // V5.2: [5.4.10] `use_device_addr` clause template // struct UseDeviceAddrT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [5.4.8] `use_device_ptr` clause template // struct UseDevicePtrT { using List = ObjectListT; using WrapperTrait = std::true_type; List v; }; // V5.2: [6.8] `uses_allocators` clause template // struct UsesAllocatorsT { using MemSpace = E; using TraitsArray = ObjectT; using Allocator = E; struct AllocatorSpec { // Not a spec name using TupleTrait = std::true_type; std::tuple t; }; using Allocators = ListT; // Not a spec name using WrapperTrait = std::true_type; Allocators v; }; // V5.2: [15.8.3] `extended-atomic` clauses template // struct WeakT { using EmptyTrait = std::true_type; }; // V5.2: [7.4.1] `when` clause template // struct WhenT { using IncompleteTrait = std::true_type; }; // V5.2: [15.8.2] Atomic clauses template // struct WriteT { using EmptyTrait = std::true_type; }; // --- template using ExtensionClausesT = std::variant, OmpxBareT, OmpxDynCgroupMemT>; template using EmptyClausesT = std::variant< AcqRelT, AcquireT, CaptureT, CompareT, DynamicAllocatorsT, FullT, InbranchT, MergeableT, NogroupT, NoOpenmpRoutinesT, NoOpenmpT, NoParallelismT, NotinbranchT, NowaitT, ReadT, RelaxedT, ReleaseT, ReverseOffloadT, SeqCstT, SimdT, ThreadsT, UnifiedAddressT, UnifiedSharedMemoryT, UnknownT, UntiedT, UseT, WeakT, WriteT>; template using IncompleteClausesT = std::variant, AppendArgsT, MatchT, OtherwiseT, WhenT>; template using TupleClausesT = std::variant, AlignedT, AllocateT, DefaultmapT, DeviceT, DistScheduleT, DoacrossT, FromT, GrainsizeT, IfT, InitT, InReductionT, LastprivateT, LinearT, MapT, NumTasksT, OrderT, ReductionT, ScheduleT, TaskReductionT, ToT>; template using UnionClausesT = std::variant>; template using WrapperClausesT = std::variant< AbsentT, AlignT, AllocatorT, AtomicDefaultMemOrderT, AtT, BindT, CollapseT, ContainsT, CopyinT, CopyprivateT, DefaultT, DestroyT, DetachT, DeviceTypeT, EnterT, ExclusiveT, FailT, FilterT, FinalT, FirstprivateT, HasDeviceAddrT, HintT, HoldsT, InclusiveT, IndirectT, InitializerT, IsDevicePtrT, LinkT, MessageT, NocontextT, NontemporalT, NovariantsT, NumTeamsT, NumThreadsT, OrderedT, PartialT, PriorityT, PrivateT, ProcBindT, SafelenT, SeverityT, SharedT, SimdlenT, SizesT, ThreadLimitT, UniformT, UpdateT, UseDeviceAddrT, UseDevicePtrT, UsesAllocatorsT>; template using UnionOfAllClausesT = typename type::Union< // EmptyClausesT, // ExtensionClausesT, // IncompleteClausesT, // TupleClausesT, // UnionClausesT, // WrapperClausesT // >::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; // // 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 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; using VariantTy = typename type::Union< clause::UnionOfAllClausesT, std::variant>::type; llvm::omp::Clause id; // The numeric id of the clause using UnionTrait = std::true_type; VariantTy u; }; template struct DirectiveWithClauses { llvm::omp::Directive id = llvm::omp::Directive::OMPD_unknown; tomp::type::ListT clauses; }; } // namespace tomp #undef OPT #undef ENUM #endif // LLVM_FRONTEND_OPENMP_CLAUSET_H