1 //===-- Clauses.h -- OpenMP clause handling -------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #ifndef FORTRAN_LOWER_OPENMP_CLAUSES_H 9 #define FORTRAN_LOWER_OPENMP_CLAUSES_H 10 11 #include "flang/Evaluate/expression.h" 12 #include "flang/Evaluate/type.h" 13 #include "flang/Parser/parse-tree.h" 14 #include "flang/Semantics/expression.h" 15 #include "flang/Semantics/semantics.h" 16 #include "flang/Semantics/symbol.h" 17 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/Frontend/OpenMP/ClauseT.h" 20 21 #include <optional> 22 #include <type_traits> 23 #include <utility> 24 25 namespace Fortran::semantics { 26 class Symbol; 27 } 28 29 namespace Fortran::lower::omp { 30 using namespace Fortran; 31 using SomeExpr = semantics::SomeExpr; 32 using MaybeExpr = semantics::MaybeExpr; 33 using TypeTy = evaluate::DynamicType; 34 35 template <typename ExprTy> 36 struct IdTyTemplate { 37 // "symbol" is always non-null for id's of actual objects. 38 Fortran::semantics::Symbol *symbol; 39 std::optional<ExprTy> designator; 40 41 bool operator==(const IdTyTemplate &other) const { 42 // If symbols are different, then the objects are different. 43 if (symbol != other.symbol) 44 return false; 45 if (symbol == nullptr) 46 return true; 47 // Equal symbols don't necessarily indicate identical objects, 48 // for example, a derived object component may use a single symbol, 49 // which will refer to different objects for different designators, 50 // e.g. a%c and b%c. 51 return designator == other.designator; 52 } 53 54 // Defining an "ordering" which allows types derived from this to be 55 // utilised in maps and other containers that require comparison 56 // operators for ordering 57 bool operator<(const IdTyTemplate &other) const { 58 return symbol < other.symbol; 59 } 60 61 operator bool() const { return symbol != nullptr; } 62 }; 63 64 using ExprTy = SomeExpr; 65 66 template <typename T> 67 using List = tomp::ListT<T>; 68 } // namespace Fortran::lower::omp 69 70 // Specialization of the ObjectT template 71 namespace tomp::type { 72 template <> 73 struct ObjectT<Fortran::lower::omp::IdTyTemplate<Fortran::lower::omp::ExprTy>, 74 Fortran::lower::omp::ExprTy> { 75 using IdTy = Fortran::lower::omp::IdTyTemplate<Fortran::lower::omp::ExprTy>; 76 using ExprTy = Fortran::lower::omp::ExprTy; 77 78 IdTy id() const { return identity; } 79 Fortran::semantics::Symbol *sym() const { return identity.symbol; } 80 const std::optional<ExprTy> &ref() const { return identity.designator; } 81 82 bool operator<(const ObjectT<IdTy, ExprTy> &other) const { 83 return identity < other.identity; 84 } 85 86 IdTy identity; 87 }; 88 } // namespace tomp::type 89 90 namespace Fortran::lower::omp { 91 using IdTy = IdTyTemplate<ExprTy>; 92 } 93 94 namespace std { 95 template <> 96 struct hash<Fortran::lower::omp::IdTy> { 97 size_t operator()(const Fortran::lower::omp::IdTy &id) const { 98 return static_cast<size_t>(reinterpret_cast<uintptr_t>(id.symbol)); 99 } 100 }; 101 } // namespace std 102 103 namespace Fortran::lower::omp { 104 using Object = tomp::ObjectT<IdTy, ExprTy>; 105 using ObjectList = tomp::ObjectListT<IdTy, ExprTy>; 106 107 Object makeObject(const parser::OmpObject &object, 108 semantics::SemanticsContext &semaCtx); 109 Object makeObject(const parser::Name &name, 110 semantics::SemanticsContext &semaCtx); 111 Object makeObject(const parser::Designator &dsg, 112 semantics::SemanticsContext &semaCtx); 113 Object makeObject(const parser::StructureComponent &comp, 114 semantics::SemanticsContext &semaCtx); 115 116 inline auto makeObjectFn(semantics::SemanticsContext &semaCtx) { 117 return [&](auto &&s) { return makeObject(s, semaCtx); }; 118 } 119 120 template <typename T> 121 SomeExpr makeExpr(T &&pftExpr, semantics::SemanticsContext &semaCtx) { 122 auto maybeExpr = evaluate::ExpressionAnalyzer(semaCtx).Analyze(pftExpr); 123 assert(maybeExpr); 124 return std::move(*maybeExpr); 125 } 126 127 inline auto makeExprFn(semantics::SemanticsContext &semaCtx) { 128 return [&](auto &&s) { return makeExpr(s, semaCtx); }; 129 } 130 131 template < 132 typename ContainerTy, typename FunctionTy, 133 typename ElemTy = typename llvm::remove_cvref_t<ContainerTy>::value_type, 134 typename ResultTy = std::invoke_result_t<FunctionTy, ElemTy>> 135 List<ResultTy> makeList(ContainerTy &&container, FunctionTy &&func) { 136 List<ResultTy> v; 137 llvm::transform(container, std::back_inserter(v), func); 138 return v; 139 } 140 141 inline ObjectList makeObjects(const parser::OmpObjectList &objects, 142 semantics::SemanticsContext &semaCtx) { 143 return makeList(objects.v, makeObjectFn(semaCtx)); 144 } 145 146 template <typename FuncTy, // 147 typename ArgTy, // 148 typename ResultTy = std::invoke_result_t<FuncTy, ArgTy>> 149 std::optional<ResultTy> maybeApply(FuncTy &&func, 150 const std::optional<ArgTy> &arg) { 151 if (!arg) 152 return std::nullopt; 153 return func(*arg); 154 } 155 156 template < // 157 typename FuncTy, // 158 typename ArgTy, // 159 typename ResultTy = 160 std::invoke_result_t<FuncTy, decltype(std::declval<ArgTy>().v)>> 161 std::optional<ResultTy> maybeApplyToV(FuncTy &&func, const ArgTy *arg) { 162 if (!arg) 163 return std::nullopt; 164 return func(arg->v); 165 } 166 167 std::optional<Object> getBaseObject(const Object &object, 168 semantics::SemanticsContext &semaCtx); 169 170 namespace clause { 171 using Range = tomp::type::RangeT<ExprTy>; 172 using Mapper = tomp::type::MapperT<IdTy, ExprTy>; 173 using Iterator = tomp::type::IteratorT<TypeTy, IdTy, ExprTy>; 174 using IteratorSpecifier = tomp::type::IteratorSpecifierT<TypeTy, IdTy, ExprTy>; 175 using DefinedOperator = tomp::type::DefinedOperatorT<IdTy, ExprTy>; 176 using ProcedureDesignator = tomp::type::ProcedureDesignatorT<IdTy, ExprTy>; 177 using ReductionOperator = tomp::type::ReductionIdentifierT<IdTy, ExprTy>; 178 using DependenceType = tomp::type::DependenceType; 179 using Prescriptiveness = tomp::type::Prescriptiveness; 180 181 // "Requires" clauses are handled early on, and the aggregated information 182 // is stored in the Symbol details of modules, programs, and subprograms. 183 // These clauses are still handled here to cover all alternatives in the 184 // main clause variant. 185 186 using Absent = tomp::clause::AbsentT<TypeTy, IdTy, ExprTy>; 187 using AcqRel = tomp::clause::AcqRelT<TypeTy, IdTy, ExprTy>; 188 using Acquire = tomp::clause::AcquireT<TypeTy, IdTy, ExprTy>; 189 using AdjustArgs = tomp::clause::AdjustArgsT<TypeTy, IdTy, ExprTy>; 190 using Affinity = tomp::clause::AffinityT<TypeTy, IdTy, ExprTy>; 191 using Aligned = tomp::clause::AlignedT<TypeTy, IdTy, ExprTy>; 192 using Align = tomp::clause::AlignT<TypeTy, IdTy, ExprTy>; 193 using Allocate = tomp::clause::AllocateT<TypeTy, IdTy, ExprTy>; 194 using Allocator = tomp::clause::AllocatorT<TypeTy, IdTy, ExprTy>; 195 using AppendArgs = tomp::clause::AppendArgsT<TypeTy, IdTy, ExprTy>; 196 using AtomicDefaultMemOrder = 197 tomp::clause::AtomicDefaultMemOrderT<TypeTy, IdTy, ExprTy>; 198 using At = tomp::clause::AtT<TypeTy, IdTy, ExprTy>; 199 using Bind = tomp::clause::BindT<TypeTy, IdTy, ExprTy>; 200 using Capture = tomp::clause::CaptureT<TypeTy, IdTy, ExprTy>; 201 using Collapse = tomp::clause::CollapseT<TypeTy, IdTy, ExprTy>; 202 using Compare = tomp::clause::CompareT<TypeTy, IdTy, ExprTy>; 203 using Contains = tomp::clause::ContainsT<TypeTy, IdTy, ExprTy>; 204 using Copyin = tomp::clause::CopyinT<TypeTy, IdTy, ExprTy>; 205 using Copyprivate = tomp::clause::CopyprivateT<TypeTy, IdTy, ExprTy>; 206 using Defaultmap = tomp::clause::DefaultmapT<TypeTy, IdTy, ExprTy>; 207 using Default = tomp::clause::DefaultT<TypeTy, IdTy, ExprTy>; 208 using Depend = tomp::clause::DependT<TypeTy, IdTy, ExprTy>; 209 using Destroy = tomp::clause::DestroyT<TypeTy, IdTy, ExprTy>; 210 using Detach = tomp::clause::DetachT<TypeTy, IdTy, ExprTy>; 211 using Device = tomp::clause::DeviceT<TypeTy, IdTy, ExprTy>; 212 using DeviceType = tomp::clause::DeviceTypeT<TypeTy, IdTy, ExprTy>; 213 using DistSchedule = tomp::clause::DistScheduleT<TypeTy, IdTy, ExprTy>; 214 using Doacross = tomp::clause::DoacrossT<TypeTy, IdTy, ExprTy>; 215 using DynamicAllocators = 216 tomp::clause::DynamicAllocatorsT<TypeTy, IdTy, ExprTy>; 217 using Enter = tomp::clause::EnterT<TypeTy, IdTy, ExprTy>; 218 using Exclusive = tomp::clause::ExclusiveT<TypeTy, IdTy, ExprTy>; 219 using Fail = tomp::clause::FailT<TypeTy, IdTy, ExprTy>; 220 using Filter = tomp::clause::FilterT<TypeTy, IdTy, ExprTy>; 221 using Final = tomp::clause::FinalT<TypeTy, IdTy, ExprTy>; 222 using Firstprivate = tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>; 223 using From = tomp::clause::FromT<TypeTy, IdTy, ExprTy>; 224 using Full = tomp::clause::FullT<TypeTy, IdTy, ExprTy>; 225 using Grainsize = tomp::clause::GrainsizeT<TypeTy, IdTy, ExprTy>; 226 using HasDeviceAddr = tomp::clause::HasDeviceAddrT<TypeTy, IdTy, ExprTy>; 227 using Hint = tomp::clause::HintT<TypeTy, IdTy, ExprTy>; 228 using Holds = tomp::clause::HoldsT<TypeTy, IdTy, ExprTy>; 229 using If = tomp::clause::IfT<TypeTy, IdTy, ExprTy>; 230 using Inbranch = tomp::clause::InbranchT<TypeTy, IdTy, ExprTy>; 231 using Inclusive = tomp::clause::InclusiveT<TypeTy, IdTy, ExprTy>; 232 using Indirect = tomp::clause::IndirectT<TypeTy, IdTy, ExprTy>; 233 using Init = tomp::clause::InitT<TypeTy, IdTy, ExprTy>; 234 using InReduction = tomp::clause::InReductionT<TypeTy, IdTy, ExprTy>; 235 using IsDevicePtr = tomp::clause::IsDevicePtrT<TypeTy, IdTy, ExprTy>; 236 using Lastprivate = tomp::clause::LastprivateT<TypeTy, IdTy, ExprTy>; 237 using Linear = tomp::clause::LinearT<TypeTy, IdTy, ExprTy>; 238 using Link = tomp::clause::LinkT<TypeTy, IdTy, ExprTy>; 239 using Map = tomp::clause::MapT<TypeTy, IdTy, ExprTy>; 240 using Match = tomp::clause::MatchT<TypeTy, IdTy, ExprTy>; 241 using Mergeable = tomp::clause::MergeableT<TypeTy, IdTy, ExprTy>; 242 using Message = tomp::clause::MessageT<TypeTy, IdTy, ExprTy>; 243 using NoOpenmp = tomp::clause::NoOpenmpT<TypeTy, IdTy, ExprTy>; 244 using NoOpenmpRoutines = tomp::clause::NoOpenmpRoutinesT<TypeTy, IdTy, ExprTy>; 245 using NoParallelism = tomp::clause::NoParallelismT<TypeTy, IdTy, ExprTy>; 246 using Nocontext = tomp::clause::NocontextT<TypeTy, IdTy, ExprTy>; 247 using Nogroup = tomp::clause::NogroupT<TypeTy, IdTy, ExprTy>; 248 using Nontemporal = tomp::clause::NontemporalT<TypeTy, IdTy, ExprTy>; 249 using Notinbranch = tomp::clause::NotinbranchT<TypeTy, IdTy, ExprTy>; 250 using Novariants = tomp::clause::NovariantsT<TypeTy, IdTy, ExprTy>; 251 using Nowait = tomp::clause::NowaitT<TypeTy, IdTy, ExprTy>; 252 using NumTasks = tomp::clause::NumTasksT<TypeTy, IdTy, ExprTy>; 253 using NumTeams = tomp::clause::NumTeamsT<TypeTy, IdTy, ExprTy>; 254 using NumThreads = tomp::clause::NumThreadsT<TypeTy, IdTy, ExprTy>; 255 using OmpxAttribute = tomp::clause::OmpxAttributeT<TypeTy, IdTy, ExprTy>; 256 using OmpxBare = tomp::clause::OmpxBareT<TypeTy, IdTy, ExprTy>; 257 using OmpxDynCgroupMem = tomp::clause::OmpxDynCgroupMemT<TypeTy, IdTy, ExprTy>; 258 using Ordered = tomp::clause::OrderedT<TypeTy, IdTy, ExprTy>; 259 using Order = tomp::clause::OrderT<TypeTy, IdTy, ExprTy>; 260 using Otherwise = tomp::clause::OtherwiseT<TypeTy, IdTy, ExprTy>; 261 using Partial = tomp::clause::PartialT<TypeTy, IdTy, ExprTy>; 262 using Priority = tomp::clause::PriorityT<TypeTy, IdTy, ExprTy>; 263 using Private = tomp::clause::PrivateT<TypeTy, IdTy, ExprTy>; 264 using ProcBind = tomp::clause::ProcBindT<TypeTy, IdTy, ExprTy>; 265 using Read = tomp::clause::ReadT<TypeTy, IdTy, ExprTy>; 266 using Reduction = tomp::clause::ReductionT<TypeTy, IdTy, ExprTy>; 267 using Relaxed = tomp::clause::RelaxedT<TypeTy, IdTy, ExprTy>; 268 using Release = tomp::clause::ReleaseT<TypeTy, IdTy, ExprTy>; 269 using ReverseOffload = tomp::clause::ReverseOffloadT<TypeTy, IdTy, ExprTy>; 270 using Safelen = tomp::clause::SafelenT<TypeTy, IdTy, ExprTy>; 271 using Schedule = tomp::clause::ScheduleT<TypeTy, IdTy, ExprTy>; 272 using SeqCst = tomp::clause::SeqCstT<TypeTy, IdTy, ExprTy>; 273 using Severity = tomp::clause::SeverityT<TypeTy, IdTy, ExprTy>; 274 using Shared = tomp::clause::SharedT<TypeTy, IdTy, ExprTy>; 275 using Simdlen = tomp::clause::SimdlenT<TypeTy, IdTy, ExprTy>; 276 using Simd = tomp::clause::SimdT<TypeTy, IdTy, ExprTy>; 277 using Sizes = tomp::clause::SizesT<TypeTy, IdTy, ExprTy>; 278 using Permutation = tomp::clause::PermutationT<TypeTy, IdTy, ExprTy>; 279 using TaskReduction = tomp::clause::TaskReductionT<TypeTy, IdTy, ExprTy>; 280 using ThreadLimit = tomp::clause::ThreadLimitT<TypeTy, IdTy, ExprTy>; 281 using Threads = tomp::clause::ThreadsT<TypeTy, IdTy, ExprTy>; 282 using To = tomp::clause::ToT<TypeTy, IdTy, ExprTy>; 283 using UnifiedAddress = tomp::clause::UnifiedAddressT<TypeTy, IdTy, ExprTy>; 284 using UnifiedSharedMemory = 285 tomp::clause::UnifiedSharedMemoryT<TypeTy, IdTy, ExprTy>; 286 using Uniform = tomp::clause::UniformT<TypeTy, IdTy, ExprTy>; 287 using Unknown = tomp::clause::UnknownT<TypeTy, IdTy, ExprTy>; 288 using Untied = tomp::clause::UntiedT<TypeTy, IdTy, ExprTy>; 289 using Update = tomp::clause::UpdateT<TypeTy, IdTy, ExprTy>; 290 using UseDeviceAddr = tomp::clause::UseDeviceAddrT<TypeTy, IdTy, ExprTy>; 291 using UseDevicePtr = tomp::clause::UseDevicePtrT<TypeTy, IdTy, ExprTy>; 292 using UsesAllocators = tomp::clause::UsesAllocatorsT<TypeTy, IdTy, ExprTy>; 293 using Use = tomp::clause::UseT<TypeTy, IdTy, ExprTy>; 294 using Weak = tomp::clause::WeakT<TypeTy, IdTy, ExprTy>; 295 using When = tomp::clause::WhenT<TypeTy, IdTy, ExprTy>; 296 using Write = tomp::clause::WriteT<TypeTy, IdTy, ExprTy>; 297 } // namespace clause 298 299 using tomp::type::operator==; 300 301 struct CancellationConstructType { 302 using EmptyTrait = std::true_type; 303 }; 304 struct Depobj { 305 using EmptyTrait = std::true_type; 306 }; 307 struct Flush { 308 using EmptyTrait = std::true_type; 309 }; 310 struct MemoryOrder { 311 using EmptyTrait = std::true_type; 312 }; 313 struct Threadprivate { 314 using EmptyTrait = std::true_type; 315 }; 316 317 using ClauseBase = tomp::ClauseT<TypeTy, IdTy, ExprTy, 318 // Extras... 319 CancellationConstructType, Depobj, Flush, 320 MemoryOrder, Threadprivate>; 321 322 struct Clause : public ClauseBase { 323 Clause(ClauseBase &&base, const parser::CharBlock source = {}) 324 : ClauseBase(std::move(base)), source(source) {} 325 // "source" will be ignored by tomp::type::operator==. 326 parser::CharBlock source; 327 }; 328 329 template <typename Specific> 330 Clause makeClause(llvm::omp::Clause id, Specific &&specific, 331 parser::CharBlock source = {}) { 332 return Clause(typename Clause::BaseT{id, specific}, source); 333 } 334 335 Clause makeClause(const parser::OmpClause &cls, 336 semantics::SemanticsContext &semaCtx); 337 338 List<Clause> makeClauses(const parser::OmpClauseList &clauses, 339 semantics::SemanticsContext &semaCtx); 340 341 bool transferLocations(const List<Clause> &from, List<Clause> &to); 342 } // namespace Fortran::lower::omp 343 344 #endif // FORTRAN_LOWER_OPENMP_CLAUSES_H 345