//===-- Clauses.h -- OpenMP clause handling -------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #ifndef FORTRAN_LOWER_OPENMP_CLAUSES_H #define FORTRAN_LOWER_OPENMP_CLAUSES_H #include "flang/Evaluate/expression.h" #include "flang/Evaluate/type.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/expression.h" #include "flang/Semantics/semantics.h" #include "flang/Semantics/symbol.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Frontend/OpenMP/ClauseT.h" #include #include #include namespace Fortran::semantics { class Symbol; } namespace Fortran::lower::omp { using namespace Fortran; using SomeExpr = semantics::SomeExpr; using MaybeExpr = semantics::MaybeExpr; using TypeTy = evaluate::DynamicType; template struct IdTyTemplate { // "symbol" is always non-null for id's of actual objects. Fortran::semantics::Symbol *symbol; std::optional designator; bool operator==(const IdTyTemplate &other) const { // If symbols are different, then the objects are different. if (symbol != other.symbol) return false; if (symbol == nullptr) return true; // Equal symbols don't necessarily indicate identical objects, // for example, a derived object component may use a single symbol, // which will refer to different objects for different designators, // e.g. a%c and b%c. return designator == other.designator; } // Defining an "ordering" which allows types derived from this to be // utilised in maps and other containers that require comparison // operators for ordering bool operator<(const IdTyTemplate &other) const { return symbol < other.symbol; } operator bool() const { return symbol != nullptr; } }; using ExprTy = SomeExpr; template using List = tomp::ListT; } // namespace Fortran::lower::omp // Specialization of the ObjectT template namespace tomp::type { template <> struct ObjectT, Fortran::lower::omp::ExprTy> { using IdTy = Fortran::lower::omp::IdTyTemplate; using ExprTy = Fortran::lower::omp::ExprTy; IdTy id() const { return identity; } Fortran::semantics::Symbol *sym() const { return identity.symbol; } const std::optional &ref() const { return identity.designator; } bool operator<(const ObjectT &other) const { return identity < other.identity; } IdTy identity; }; } // namespace tomp::type namespace Fortran::lower::omp { using IdTy = IdTyTemplate; } namespace std { template <> struct hash { size_t operator()(const Fortran::lower::omp::IdTy &id) const { return static_cast(reinterpret_cast(id.symbol)); } }; } // namespace std namespace Fortran::lower::omp { using Object = tomp::ObjectT; using ObjectList = tomp::ObjectListT; Object makeObject(const parser::OmpObject &object, semantics::SemanticsContext &semaCtx); Object makeObject(const parser::Name &name, semantics::SemanticsContext &semaCtx); Object makeObject(const parser::Designator &dsg, semantics::SemanticsContext &semaCtx); Object makeObject(const parser::StructureComponent &comp, semantics::SemanticsContext &semaCtx); inline auto makeObjectFn(semantics::SemanticsContext &semaCtx) { return [&](auto &&s) { return makeObject(s, semaCtx); }; } template SomeExpr makeExpr(T &&pftExpr, semantics::SemanticsContext &semaCtx) { auto maybeExpr = evaluate::ExpressionAnalyzer(semaCtx).Analyze(pftExpr); assert(maybeExpr); return std::move(*maybeExpr); } inline auto makeExprFn(semantics::SemanticsContext &semaCtx) { return [&](auto &&s) { return makeExpr(s, semaCtx); }; } template < typename ContainerTy, typename FunctionTy, typename ElemTy = typename llvm::remove_cvref_t::value_type, typename ResultTy = std::invoke_result_t> List makeList(ContainerTy &&container, FunctionTy &&func) { List v; llvm::transform(container, std::back_inserter(v), func); return v; } inline ObjectList makeObjects(const parser::OmpObjectList &objects, semantics::SemanticsContext &semaCtx) { return makeList(objects.v, makeObjectFn(semaCtx)); } template > std::optional maybeApply(FuncTy &&func, const std::optional &arg) { if (!arg) return std::nullopt; return func(*arg); } template < // typename FuncTy, // typename ArgTy, // typename ResultTy = std::invoke_result_t().v)>> std::optional maybeApplyToV(FuncTy &&func, const ArgTy *arg) { if (!arg) return std::nullopt; return func(arg->v); } std::optional getBaseObject(const Object &object, semantics::SemanticsContext &semaCtx); namespace clause { using Range = tomp::type::RangeT; using Mapper = tomp::type::MapperT; using Iterator = tomp::type::IteratorT; using IteratorSpecifier = tomp::type::IteratorSpecifierT; using DefinedOperator = tomp::type::DefinedOperatorT; using ProcedureDesignator = tomp::type::ProcedureDesignatorT; using ReductionOperator = tomp::type::ReductionIdentifierT; using DependenceType = tomp::type::DependenceType; using Prescriptiveness = tomp::type::Prescriptiveness; // "Requires" clauses are handled early on, and the aggregated information // is stored in the Symbol details of modules, programs, and subprograms. // These clauses are still handled here to cover all alternatives in the // main clause variant. using Absent = tomp::clause::AbsentT; using AcqRel = tomp::clause::AcqRelT; using Acquire = tomp::clause::AcquireT; using AdjustArgs = tomp::clause::AdjustArgsT; using Affinity = tomp::clause::AffinityT; using Aligned = tomp::clause::AlignedT; using Align = tomp::clause::AlignT; using Allocate = tomp::clause::AllocateT; using Allocator = tomp::clause::AllocatorT; using AppendArgs = tomp::clause::AppendArgsT; using AtomicDefaultMemOrder = tomp::clause::AtomicDefaultMemOrderT; using At = tomp::clause::AtT; using Bind = tomp::clause::BindT; using Capture = tomp::clause::CaptureT; using Collapse = tomp::clause::CollapseT; using Compare = tomp::clause::CompareT; using Contains = tomp::clause::ContainsT; using Copyin = tomp::clause::CopyinT; using Copyprivate = tomp::clause::CopyprivateT; using Defaultmap = tomp::clause::DefaultmapT; using Default = tomp::clause::DefaultT; using Depend = tomp::clause::DependT; using Destroy = tomp::clause::DestroyT; using Detach = tomp::clause::DetachT; using Device = tomp::clause::DeviceT; using DeviceType = tomp::clause::DeviceTypeT; using DistSchedule = tomp::clause::DistScheduleT; using Doacross = tomp::clause::DoacrossT; using DynamicAllocators = tomp::clause::DynamicAllocatorsT; using Enter = tomp::clause::EnterT; using Exclusive = tomp::clause::ExclusiveT; using Fail = tomp::clause::FailT; using Filter = tomp::clause::FilterT; using Final = tomp::clause::FinalT; using Firstprivate = tomp::clause::FirstprivateT; using From = tomp::clause::FromT; using Full = tomp::clause::FullT; using Grainsize = tomp::clause::GrainsizeT; using HasDeviceAddr = tomp::clause::HasDeviceAddrT; using Hint = tomp::clause::HintT; using Holds = tomp::clause::HoldsT; using If = tomp::clause::IfT; using Inbranch = tomp::clause::InbranchT; using Inclusive = tomp::clause::InclusiveT; using Indirect = tomp::clause::IndirectT; using Init = tomp::clause::InitT; using InReduction = tomp::clause::InReductionT; using IsDevicePtr = tomp::clause::IsDevicePtrT; using Lastprivate = tomp::clause::LastprivateT; using Linear = tomp::clause::LinearT; using Link = tomp::clause::LinkT; using Map = tomp::clause::MapT; using Match = tomp::clause::MatchT; using Mergeable = tomp::clause::MergeableT; using Message = tomp::clause::MessageT; using NoOpenmp = tomp::clause::NoOpenmpT; using NoOpenmpRoutines = tomp::clause::NoOpenmpRoutinesT; using NoParallelism = tomp::clause::NoParallelismT; using Nocontext = tomp::clause::NocontextT; using Nogroup = tomp::clause::NogroupT; using Nontemporal = tomp::clause::NontemporalT; using Notinbranch = tomp::clause::NotinbranchT; using Novariants = tomp::clause::NovariantsT; using Nowait = tomp::clause::NowaitT; using NumTasks = tomp::clause::NumTasksT; using NumTeams = tomp::clause::NumTeamsT; using NumThreads = tomp::clause::NumThreadsT; using OmpxAttribute = tomp::clause::OmpxAttributeT; using OmpxBare = tomp::clause::OmpxBareT; using OmpxDynCgroupMem = tomp::clause::OmpxDynCgroupMemT; using Ordered = tomp::clause::OrderedT; using Order = tomp::clause::OrderT; using Partial = tomp::clause::PartialT; using Priority = tomp::clause::PriorityT; using Private = tomp::clause::PrivateT; using ProcBind = tomp::clause::ProcBindT; using Read = tomp::clause::ReadT; using Reduction = tomp::clause::ReductionT; using Relaxed = tomp::clause::RelaxedT; using Release = tomp::clause::ReleaseT; using ReverseOffload = tomp::clause::ReverseOffloadT; using Safelen = tomp::clause::SafelenT; using Schedule = tomp::clause::ScheduleT; using SeqCst = tomp::clause::SeqCstT; using Severity = tomp::clause::SeverityT; using Shared = tomp::clause::SharedT; using Simdlen = tomp::clause::SimdlenT; using Simd = tomp::clause::SimdT; using Sizes = tomp::clause::SizesT; using Permutation = tomp::clause::PermutationT; using TaskReduction = tomp::clause::TaskReductionT; using ThreadLimit = tomp::clause::ThreadLimitT; using Threads = tomp::clause::ThreadsT; using To = tomp::clause::ToT; using UnifiedAddress = tomp::clause::UnifiedAddressT; using UnifiedSharedMemory = tomp::clause::UnifiedSharedMemoryT; using Uniform = tomp::clause::UniformT; using Unknown = tomp::clause::UnknownT; using Untied = tomp::clause::UntiedT; using Update = tomp::clause::UpdateT; using UseDeviceAddr = tomp::clause::UseDeviceAddrT; using UseDevicePtr = tomp::clause::UseDevicePtrT; using UsesAllocators = tomp::clause::UsesAllocatorsT; using Use = tomp::clause::UseT; using Weak = tomp::clause::WeakT; using When = tomp::clause::WhenT; using Write = tomp::clause::WriteT; } // namespace clause using tomp::type::operator==; struct CancellationConstructType { using EmptyTrait = std::true_type; }; struct Depobj { using EmptyTrait = std::true_type; }; struct Flush { using EmptyTrait = std::true_type; }; struct MemoryOrder { using EmptyTrait = std::true_type; }; struct Threadprivate { using EmptyTrait = std::true_type; }; using ClauseBase = tomp::ClauseT; struct Clause : public ClauseBase { Clause(ClauseBase &&base, const parser::CharBlock source = {}) : ClauseBase(std::move(base)), source(source) {} // "source" will be ignored by tomp::type::operator==. parser::CharBlock source; }; template Clause makeClause(llvm::omp::Clause id, Specific &&specific, parser::CharBlock source = {}) { return Clause(typename Clause::BaseT{id, specific}, source); } Clause makeClause(const parser::OmpClause &cls, semantics::SemanticsContext &semaCtx); List makeClauses(const parser::OmpClauseList &clauses, semantics::SemanticsContext &semaCtx); bool transferLocations(const List &from, List &to); } // namespace Fortran::lower::omp #endif // FORTRAN_LOWER_OPENMP_CLAUSES_H