xref: /llvm-project/flang/lib/Lower/OpenMP/Clauses.h (revision 15ab7be2e049bc0f4ea6744ca037395686a923bc)
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