llvm/llvm/include/llvm/Frontend/OpenMP/ClauseT.h

//===- 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
#define OPT

// 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)

// Helper macro for enum (non-class) conversion.
#define CLAUSET_UNSCOPED_ENUM_MEMBER_CONVERT(Ov, Tv)

#define CLAUSET_ENUM_CONVERT(func, OtherE, ThisE, Maps)

// 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 {};

is_variant<std::variant<Ts...>>;

is_variant_v;

// Helper utility to create a type which is a union of two given variants.
template <typename...> struct UnionOfTwo;

UnionOfTwo<std::variant<Types1...>, std::variant<Types2...>>;
} // namespace detail

namespace tomp {
type // namespace type

ListT;

ObjectT;
ObjectListT;

IteratorT;

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) {}

namespace clause {
operator==;

// V5.2: [8.3.1] `assumption` clauses
template <typename T, typename I, typename E> //
struct AbsentT {};

// V5.2: [15.8.1] `memory-order` clauses
template <typename T, typename I, typename E> //
struct AcqRelT {};

// V5.2: [15.8.1] `memory-order` clauses
template <typename T, typename I, typename E> //
struct AcquireT {};

// V5.2: [7.5.2] `adjust_args` clause
template <typename T, typename I, typename E> //
struct AdjustArgsT {};

// V5.2: [12.5.1] `affinity` clause
template <typename T, typename I, typename E> //
struct AffinityT {};

// V5.2: [6.3] `align` clause
template <typename T, typename I, typename E> //
struct AlignT {};

// V5.2: [5.11] `aligned` clause
template <typename T, typename I, typename E> //
struct AlignedT {};

template <typename T, typename I, typename E> //
struct AllocatorT;

// V5.2: [6.6] `allocate` clause
template <typename T, typename I, typename E> //
struct AllocateT {};

// V5.2: [6.4] `allocator` clause
template <typename T, typename I, typename E> //
struct AllocatorT {};

// V5.2: [7.5.3] `append_args` clause
template <typename T, typename I, typename E> //
struct AppendArgsT {};

// V5.2: [8.1] `at` clause
template <typename T, typename I, typename E> //
struct AtT {};

// V5.2: [8.2.1] `requirement` clauses
template <typename T, typename I, typename E> //
struct AtomicDefaultMemOrderT {};

// V5.2: [11.7.1] `bind` clause
template <typename T, typename I, typename E> //
struct BindT {};

// V5.2: [15.8.3] `extended-atomic` clauses
template <typename T, typename I, typename E> //
struct CaptureT {};

// V5.2: [4.4.3] `collapse` clause
template <typename T, typename I, typename E> //
struct CollapseT {};

// V5.2: [15.8.3] `extended-atomic` clauses
template <typename T, typename I, typename E> //
struct CompareT {};

// V5.2: [8.3.1] `assumption` clauses
template <typename T, typename I, typename E> //
struct ContainsT {};

// V5.2: [5.7.1] `copyin` clause
template <typename T, typename I, typename E> //
struct CopyinT {};

// V5.2: [5.7.2] `copyprivate` clause
template <typename T, typename I, typename E> //
struct CopyprivateT {};

// V5.2: [5.4.1] `default` clause
template <typename T, typename I, typename E> //
struct DefaultT {};

// V5.2: [5.8.7] `defaultmap` clause
template <typename T, typename I, typename E> //
struct DefaultmapT {};

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 {};

// V5.2: [3.5] `destroy` clause
template <typename T, typename I, typename E> //
struct DestroyT {};

// V5.2: [12.5.2] `detach` clause
template <typename T, typename I, typename E> //
struct DetachT {};

// V5.2: [13.2] `device` clause
template <typename T, typename I, typename E> //
struct DeviceT {};

// V5.2: [13.1] `device_type` clause
template <typename T, typename I, typename E> //
struct DeviceTypeT {};

// V5.2: [11.6.1] `dist_schedule` clause
template <typename T, typename I, typename E> //
struct DistScheduleT {};

// V5.2: [15.9.6] `doacross` clause
template <typename T, typename I, typename E> //
struct DoacrossT {};

// V5.2: [8.2.1] `requirement` clauses
template <typename T, typename I, typename E> //
struct DynamicAllocatorsT {};

// V5.2: [5.8.4] `enter` clause
template <typename T, typename I, typename E> //
struct EnterT {};

// V5.2: [5.6.2] `exclusive` clause
template <typename T, typename I, typename E> //
struct ExclusiveT {};

// V5.2: [15.8.3] `extended-atomic` clauses
template <typename T, typename I, typename E> //
struct FailT {};

// V5.2: [10.5.1] `filter` clause
template <typename T, typename I, typename E> //
struct FilterT {};

// V5.2: [12.3] `final` clause
template <typename T, typename I, typename E> //
struct FinalT {};

// V5.2: [5.4.4] `firstprivate` clause
template <typename T, typename I, typename E> //
struct FirstprivateT {};

// V5.2: [5.9.2] `from` clause
template <typename T, typename I, typename E> //
struct FromT {};

// V5.2: [9.2.1] `full` clause
template <typename T, typename I, typename E> //
struct FullT {};

// V5.2: [12.6.1] `grainsize` clause
template <typename T, typename I, typename E> //
struct GrainsizeT {};

// V5.2: [5.4.9] `has_device_addr` clause
template <typename T, typename I, typename E> //
struct HasDeviceAddrT {};

// V5.2: [15.1.2] `hint` clause
template <typename T, typename I, typename E> //
struct HintT {};

// V5.2: [8.3.1] Assumption clauses
template <typename T, typename I, typename E> //
struct HoldsT {};

// V5.2: [3.4] `if` clause
template <typename T, typename I, typename E> //
struct IfT {};

// V5.2: [7.7.1] `branch` clauses
template <typename T, typename I, typename E> //
struct InbranchT {};

// V5.2: [5.6.1] `exclusive` clause
template <typename T, typename I, typename E> //
struct InclusiveT {};

// V5.2: [7.8.3] `indirect` clause
template <typename T, typename I, typename E> //
struct IndirectT {};

// V5.2: [14.1.2] `init` clause
template <typename T, typename I, typename E> //
struct InitT {};

// V5.2: [5.5.4] `initializer` clause
template <typename T, typename I, typename E> //
struct InitializerT {};

// V5.2: [5.5.10] `in_reduction` clause
template <typename T, typename I, typename E> //
struct InReductionT {};

// V5.2: [5.4.7] `is_device_ptr` clause
template <typename T, typename I, typename E> //
struct IsDevicePtrT {};

// V5.2: [5.4.5] `lastprivate` clause
template <typename T, typename I, typename E> //
struct LastprivateT {};

// V5.2: [5.4.6] `linear` clause
template <typename T, typename I, typename E> //
struct LinearT {};

// V5.2: [5.8.5] `link` clause
template <typename T, typename I, typename E> //
struct LinkT {};

// V5.2: [5.8.3] `map` clause
template <typename T, typename I, typename E> //
struct MapT {};

// V5.2: [7.5.1] `match` clause
template <typename T, typename I, typename E> //
struct MatchT {};

// V5.2: [12.2] `mergeable` clause
template <typename T, typename I, typename E> //
struct MergeableT {};

// V5.2: [8.5.2] `message` clause
template <typename T, typename I, typename E> //
struct MessageT {};

// V5.2: [7.6.2] `nocontext` clause
template <typename T, typename I, typename E> //
struct NocontextT {};

// V5.2: [15.7] `nowait` clause
template <typename T, typename I, typename E> //
struct NogroupT {};

// V5.2: [10.4.1] `nontemporal` clause
template <typename T, typename I, typename E> //
struct NontemporalT {};

// V5.2: [8.3.1] `assumption` clauses
template <typename T, typename I, typename E> //
struct NoOpenmpT {};

// V5.2: [8.3.1] `assumption` clauses
template <typename T, typename I, typename E> //
struct NoOpenmpRoutinesT {};

// V5.2: [8.3.1] `assumption` clauses
template <typename T, typename I, typename E> //
struct NoParallelismT {};

// V5.2: [7.7.1] `branch` clauses
template <typename T, typename I, typename E> //
struct NotinbranchT {};

// V5.2: [7.6.1] `novariants` clause
template <typename T, typename I, typename E> //
struct NovariantsT {};

// V5.2: [15.6] `nowait` clause
template <typename T, typename I, typename E> //
struct NowaitT {};

// V5.2: [12.6.2] `num_tasks` clause
template <typename T, typename I, typename E> //
struct NumTasksT {};

// V5.2: [10.2.1] `num_teams` clause
template <typename T, typename I, typename E> //
struct NumTeamsT {};

// V5.2: [10.1.2] `num_threads` clause
template <typename T, typename I, typename E> //
struct NumThreadsT {};

template <typename T, typename I, typename E> //
struct OmpxAttributeT {};

template <typename T, typename I, typename E> //
struct OmpxBareT {};

template <typename T, typename I, typename E> //
struct OmpxDynCgroupMemT {};

// V5.2: [10.3] `order` clause
template <typename T, typename I, typename E> //
struct OrderT {};

// V5.2: [4.4.4] `ordered` clause
template <typename T, typename I, typename E> //
struct OrderedT {};

// V5.2: [7.4.2] `otherwise` clause
template <typename T, typename I, typename E> //
struct OtherwiseT {};

// V5.2: [9.2.2] `partial` clause
template <typename T, typename I, typename E> //
struct PartialT {};

// V5.2: [12.4] `priority` clause
template <typename T, typename I, typename E> //
struct PriorityT {};

// V5.2: [5.4.3] `private` clause
template <typename T, typename I, typename E> //
struct PrivateT {};

// V5.2: [10.1.4] `proc_bind` clause
template <typename T, typename I, typename E> //
struct ProcBindT {};

// V5.2: [15.8.2] Atomic clauses
template <typename T, typename I, typename E> //
struct ReadT {};

// V5.2: [5.5.8] `reduction` clause
template <typename T, typename I, typename E> //
struct ReductionT {};

// V5.2: [15.8.1] `memory-order` clauses
template <typename T, typename I, typename E> //
struct RelaxedT {};

// V5.2: [15.8.1] `memory-order` clauses
template <typename T, typename I, typename E> //
struct ReleaseT {};

// V5.2: [8.2.1] `requirement` clauses
template <typename T, typename I, typename E> //
struct ReverseOffloadT {};

// V5.2: [10.4.2] `safelen` clause
template <typename T, typename I, typename E> //
struct SafelenT {};

// V5.2: [11.5.3] `schedule` clause
template <typename T, typename I, typename E> //
struct ScheduleT {};

// V5.2: [15.8.1] Memory-order clauses
template <typename T, typename I, typename E> //
struct SeqCstT {};

// V5.2: [8.5.1] `severity` clause
template <typename T, typename I, typename E> //
struct SeverityT {};

// V5.2: [5.4.2] `shared` clause
template <typename T, typename I, typename E> //
struct SharedT {};

// V5.2: [15.10.3] `parallelization-level` clauses
template <typename T, typename I, typename E> //
struct SimdT {};

// V5.2: [10.4.3] `simdlen` clause
template <typename T, typename I, typename E> //
struct SimdlenT {};

// V5.2: [9.1.1] `sizes` clause
template <typename T, typename I, typename E> //
struct SizesT {};

// V5.2: [5.5.9] `task_reduction` clause
template <typename T, typename I, typename E> //
struct TaskReductionT {};

// V5.2: [13.3] `thread_limit` clause
template <typename T, typename I, typename E> //
struct ThreadLimitT {};

// V5.2: [15.10.3] `parallelization-level` clauses
template <typename T, typename I, typename E> //
struct ThreadsT {};

// V5.2: [5.9.1] `to` clause
template <typename T, typename I, typename E> //
struct ToT {};

// V5.2: [8.2.1] `requirement` clauses
template <typename T, typename I, typename E> //
struct UnifiedAddressT {};

// V5.2: [8.2.1] `requirement` clauses
template <typename T, typename I, typename E> //
struct UnifiedSharedMemoryT {};

// V5.2: [5.10] `uniform` clause
template <typename T, typename I, typename E> //
struct UniformT {};

template <typename T, typename I, typename E> //
struct UnknownT {};

// V5.2: [12.1] `untied` clause
template <typename T, typename I, typename E> //
struct UntiedT {};

// 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 {};

// V5.2: [14.1.3] `use` clause
template <typename T, typename I, typename E> //
struct UseT {};

// V5.2: [5.4.10] `use_device_addr` clause
template <typename T, typename I, typename E> //
struct UseDeviceAddrT {};

// V5.2: [5.4.8] `use_device_ptr` clause
template <typename T, typename I, typename E> //
struct UseDevicePtrT {};

// V5.2: [6.8] `uses_allocators` clause
template <typename T, typename I, typename E> //
struct UsesAllocatorsT {};

// V5.2: [15.8.3] `extended-atomic` clauses
template <typename T, typename I, typename E> //
struct WeakT {};

// V5.2: [7.4.1] `when` clause
template <typename T, typename I, typename E> //
struct WhenT {};

// V5.2: [15.8.2] Atomic clauses
template <typename T, typename I, typename E> //
struct WriteT {};

// ---

ExtensionClausesT;

EmptyClausesT;

IncompleteClausesT;

TupleClausesT;

UnionClausesT;

WrapperClausesT;

UnionOfAllClausesT;
} // namespace clause

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 {};

template <typename ClauseType> struct DirectiveWithClauses {};

} // namespace tomp

#undef OPT
#undef ENUM

#endif // LLVM_FRONTEND_OPENMP_CLAUSET_H