1 | //===-- Clauses.cpp -- 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 | |
9 | #include "Clauses.h" |
10 | |
11 | #include "flang/Common/idioms.h" |
12 | #include "flang/Evaluate/expression.h" |
13 | #include "flang/Optimizer/Builder/Todo.h" |
14 | #include "flang/Parser/parse-tree.h" |
15 | #include "flang/Semantics/expression.h" |
16 | #include "flang/Semantics/openmp-modifiers.h" |
17 | #include "flang/Semantics/symbol.h" |
18 | |
19 | #include "llvm/Frontend/OpenMP/OMPConstants.h" |
20 | |
21 | #include <list> |
22 | #include <optional> |
23 | #include <tuple> |
24 | #include <utility> |
25 | #include <variant> |
26 | |
27 | namespace Fortran::lower::omp { |
28 | using SymbolWithDesignator = std::tuple<semantics::Symbol *, MaybeExpr>; |
29 | |
30 | struct SymbolAndDesignatorExtractor { |
31 | template <typename T> |
32 | static T &&AsRvalueRef(T &&t) { |
33 | return std::move(t); |
34 | } |
35 | template <typename T> |
36 | static T AsRvalueRef(const T &t) { |
37 | return t; |
38 | } |
39 | |
40 | static semantics::Symbol *symbol_addr(const evaluate::SymbolRef &ref) { |
41 | // Symbols cannot be created after semantic checks, so all symbol |
42 | // pointers that are non-null must point to one of those pre-existing |
43 | // objects. Throughout the code, symbols are often pointed to by |
44 | // non-const pointers, so there is no harm in casting the constness |
45 | // away. |
46 | return const_cast<semantics::Symbol *>(&ref.get()); |
47 | } |
48 | |
49 | template <typename T> |
50 | static SymbolWithDesignator visit(T &&) { |
51 | // Use this to see missing overloads: |
52 | // llvm::errs() << "NULL: " << __PRETTY_FUNCTION__ << '\n'; |
53 | return SymbolWithDesignator{}; |
54 | } |
55 | |
56 | template <typename T> |
57 | static SymbolWithDesignator visit(const evaluate::Designator<T> &e) { |
58 | return std::make_tuple(symbol_addr(*e.GetLastSymbol()), |
59 | evaluate::AsGenericExpr(AsRvalueRef(e))); |
60 | } |
61 | |
62 | static SymbolWithDesignator visit(const evaluate::ProcedureDesignator &e) { |
63 | return std::make_tuple(symbol_addr(*e.GetSymbol()), std::nullopt); |
64 | } |
65 | |
66 | template <typename T> |
67 | static SymbolWithDesignator visit(const evaluate::Expr<T> &e) { |
68 | return Fortran::common::visit([](auto &&s) { return visit(s); }, e.u); |
69 | } |
70 | |
71 | static void verify(const SymbolWithDesignator &sd) { |
72 | const semantics::Symbol *symbol = std::get<0>(sd); |
73 | assert(symbol && "Expecting symbol" ); |
74 | auto &maybeDsg = std::get<1>(sd); |
75 | if (!maybeDsg) |
76 | return; // Symbol with no designator -> OK |
77 | std::optional<evaluate::DataRef> maybeRef = |
78 | evaluate::ExtractDataRef(*maybeDsg); |
79 | if (maybeRef) { |
80 | if (&maybeRef->GetLastSymbol() == symbol) |
81 | return; // Symbol with a designator for it -> OK |
82 | llvm_unreachable("Expecting designator for given symbol" ); |
83 | } else { |
84 | // This could still be a Substring or ComplexPart, but at least Substring |
85 | // is not allowed in OpenMP. |
86 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
87 | maybeDsg->dump(); |
88 | #endif |
89 | llvm_unreachable("Expecting DataRef designator" ); |
90 | } |
91 | } |
92 | }; |
93 | |
94 | SymbolWithDesignator getSymbolAndDesignator(const MaybeExpr &expr) { |
95 | if (!expr) |
96 | return SymbolWithDesignator{}; |
97 | return Fortran::common::visit( |
98 | [](auto &&s) { return SymbolAndDesignatorExtractor::visit(s); }, expr->u); |
99 | } |
100 | |
101 | Object makeObject(const parser::Name &name, |
102 | semantics::SemanticsContext &semaCtx) { |
103 | assert(name.symbol && "Expecting Symbol" ); |
104 | return Object{name.symbol, std::nullopt}; |
105 | } |
106 | |
107 | Object makeObject(const parser::Designator &dsg, |
108 | semantics::SemanticsContext &semaCtx) { |
109 | evaluate::ExpressionAnalyzer ea{semaCtx}; |
110 | SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(dsg)); |
111 | SymbolAndDesignatorExtractor::verify(sd); |
112 | return Object{std::get<0>(sd), std::move(std::get<1>(sd))}; |
113 | } |
114 | |
115 | Object makeObject(const parser::StructureComponent &comp, |
116 | semantics::SemanticsContext &semaCtx) { |
117 | evaluate::ExpressionAnalyzer ea{semaCtx}; |
118 | SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(comp)); |
119 | SymbolAndDesignatorExtractor::verify(sd); |
120 | return Object{std::get<0>(sd), std::move(std::get<1>(sd))}; |
121 | } |
122 | |
123 | Object makeObject(const parser::OmpObject &object, |
124 | semantics::SemanticsContext &semaCtx) { |
125 | // If object is a common block, expression analyzer won't be able to |
126 | // do anything. |
127 | if (const auto *name = std::get_if<parser::Name>(&object.u)) { |
128 | assert(name->symbol && "Expecting Symbol" ); |
129 | return Object{name->symbol, std::nullopt}; |
130 | } |
131 | // OmpObject is std::variant<Designator, /*common block*/ Name>; |
132 | return makeObject(std::get<parser::Designator>(object.u), semaCtx); |
133 | } |
134 | |
135 | ObjectList makeObjects(const parser::OmpArgumentList &objects, |
136 | semantics::SemanticsContext &semaCtx) { |
137 | return makeList(objects.v, [&](const parser::OmpArgument &arg) { |
138 | return common::visit( |
139 | common::visitors{ |
140 | [&](const parser::OmpLocator &locator) -> Object { |
141 | if (auto *object = std::get_if<parser::OmpObject>(&locator.u)) { |
142 | return makeObject(*object, semaCtx); |
143 | } |
144 | llvm_unreachable("Expecting object" ); |
145 | }, |
146 | [](auto &&s) -> Object { // |
147 | llvm_unreachable("Expecting object" ); |
148 | }, |
149 | }, |
150 | arg.u); |
151 | }); |
152 | } |
153 | |
154 | std::optional<Object> getBaseObject(const Object &object, |
155 | semantics::SemanticsContext &semaCtx) { |
156 | // If it's just the symbol, then there is no base. |
157 | if (!object.ref()) |
158 | return std::nullopt; |
159 | |
160 | auto maybeRef = evaluate::ExtractDataRef(*object.ref()); |
161 | if (!maybeRef) |
162 | return std::nullopt; |
163 | |
164 | evaluate::DataRef ref = *maybeRef; |
165 | |
166 | if (std::get_if<evaluate::SymbolRef>(&ref.u)) { |
167 | return std::nullopt; |
168 | } else if (auto *comp = std::get_if<evaluate::Component>(&ref.u)) { |
169 | const evaluate::DataRef &base = comp->base(); |
170 | return Object{ |
171 | SymbolAndDesignatorExtractor::symbol_addr(base.GetLastSymbol()), |
172 | evaluate::AsGenericExpr( |
173 | SymbolAndDesignatorExtractor::AsRvalueRef(base))}; |
174 | } else if (auto *arr = std::get_if<evaluate::ArrayRef>(&ref.u)) { |
175 | const evaluate::NamedEntity &base = arr->base(); |
176 | evaluate::ExpressionAnalyzer ea{semaCtx}; |
177 | if (auto *comp = base.UnwrapComponent()) { |
178 | return Object{SymbolAndDesignatorExtractor::symbol_addr(comp->symbol()), |
179 | ea.Designate(evaluate::DataRef{ |
180 | SymbolAndDesignatorExtractor::AsRvalueRef(*comp)})}; |
181 | } else if (auto *symRef = base.UnwrapSymbolRef()) { |
182 | // This is the base symbol of the array reference, which is the same |
183 | // as the symbol in the input object, |
184 | // e.g. A(i) is represented as {Symbol(A), Designator(ArrayRef(A, i))}. |
185 | // Here we have the Symbol(A), which is what we started with. |
186 | (void)symRef; |
187 | assert(&**symRef == object.sym()); |
188 | return std::nullopt; |
189 | } |
190 | } else { |
191 | assert(std::holds_alternative<evaluate::CoarrayRef>(ref.u) && |
192 | "Unexpected variant alternative" ); |
193 | llvm_unreachable("Coarray reference not supported at the moment" ); |
194 | } |
195 | return std::nullopt; |
196 | } |
197 | |
198 | // Helper macros |
199 | #define MAKE_EMPTY_CLASS(cls, from_cls) \ |
200 | cls make(const parser::OmpClause::from_cls &, \ |
201 | semantics::SemanticsContext &) { \ |
202 | static_assert(cls::EmptyTrait::value); \ |
203 | return cls{}; \ |
204 | } \ |
205 | [[maybe_unused]] extern int xyzzy_semicolon_absorber |
206 | |
207 | #define MAKE_INCOMPLETE_CLASS(cls, from_cls) \ |
208 | cls make(const parser::OmpClause::from_cls &, \ |
209 | semantics::SemanticsContext &) { \ |
210 | static_assert(cls::IncompleteTrait::value); \ |
211 | return cls{}; \ |
212 | } \ |
213 | [[maybe_unused]] extern int xyzzy_semicolon_absorber |
214 | |
215 | #define MS(x, y) CLAUSET_SCOPED_ENUM_MEMBER_CONVERT(x, y) |
216 | #define MU(x, y) CLAUSET_UNSCOPED_ENUM_MEMBER_CONVERT(x, y) |
217 | |
218 | namespace clause { |
219 | MAKE_EMPTY_CLASS(AcqRel, AcqRel); |
220 | MAKE_EMPTY_CLASS(Acquire, Acquire); |
221 | MAKE_EMPTY_CLASS(Capture, Capture); |
222 | MAKE_EMPTY_CLASS(Compare, Compare); |
223 | MAKE_EMPTY_CLASS(DynamicAllocators, DynamicAllocators); |
224 | MAKE_EMPTY_CLASS(Full, Full); |
225 | MAKE_EMPTY_CLASS(Inbranch, Inbranch); |
226 | MAKE_EMPTY_CLASS(Mergeable, Mergeable); |
227 | MAKE_EMPTY_CLASS(Nogroup, Nogroup); |
228 | MAKE_EMPTY_CLASS(NoOpenmp, NoOpenmp); |
229 | MAKE_EMPTY_CLASS(NoOpenmpRoutines, NoOpenmpRoutines); |
230 | MAKE_EMPTY_CLASS(NoOpenmpConstructs, NoOpenmpConstructs); |
231 | MAKE_EMPTY_CLASS(NoParallelism, NoParallelism); |
232 | MAKE_EMPTY_CLASS(Notinbranch, Notinbranch); |
233 | MAKE_EMPTY_CLASS(Nowait, Nowait); |
234 | MAKE_EMPTY_CLASS(OmpxAttribute, OmpxAttribute); |
235 | MAKE_EMPTY_CLASS(OmpxBare, OmpxBare); |
236 | MAKE_EMPTY_CLASS(Read, Read); |
237 | MAKE_EMPTY_CLASS(Relaxed, Relaxed); |
238 | MAKE_EMPTY_CLASS(Release, Release); |
239 | MAKE_EMPTY_CLASS(ReverseOffload, ReverseOffload); |
240 | MAKE_EMPTY_CLASS(SeqCst, SeqCst); |
241 | MAKE_EMPTY_CLASS(Simd, Simd); |
242 | MAKE_EMPTY_CLASS(Threads, Threads); |
243 | MAKE_EMPTY_CLASS(UnifiedAddress, UnifiedAddress); |
244 | MAKE_EMPTY_CLASS(UnifiedSharedMemory, UnifiedSharedMemory); |
245 | MAKE_EMPTY_CLASS(SelfMaps, SelfMaps); |
246 | MAKE_EMPTY_CLASS(Unknown, Unknown); |
247 | MAKE_EMPTY_CLASS(Untied, Untied); |
248 | MAKE_EMPTY_CLASS(Weak, Weak); |
249 | MAKE_EMPTY_CLASS(Write, Write); |
250 | |
251 | // Artificial clauses |
252 | MAKE_EMPTY_CLASS(Depobj, Depobj); |
253 | MAKE_EMPTY_CLASS(Flush, Flush); |
254 | MAKE_EMPTY_CLASS(MemoryOrder, MemoryOrder); |
255 | MAKE_EMPTY_CLASS(Threadprivate, Threadprivate); |
256 | |
257 | MAKE_INCOMPLETE_CLASS(AdjustArgs, AdjustArgs); |
258 | MAKE_INCOMPLETE_CLASS(AppendArgs, AppendArgs); |
259 | |
260 | List<IteratorSpecifier> |
261 | makeIteratorSpecifiers(const parser::OmpIteratorSpecifier &inp, |
262 | semantics::SemanticsContext &semaCtx) { |
263 | List<IteratorSpecifier> specifiers; |
264 | |
265 | auto &[begin, end, step] = std::get<parser::SubscriptTriplet>(inp.t).t; |
266 | assert(begin && end && "Expecting begin/end values" ); |
267 | evaluate::ExpressionAnalyzer ea{semaCtx}; |
268 | |
269 | MaybeExpr rbegin{ea.Analyze(*begin)}, rend{ea.Analyze(*end)}; |
270 | MaybeExpr rstep; |
271 | if (step) |
272 | rstep = ea.Analyze(*step); |
273 | |
274 | assert(rbegin && rend && "Unable to get range bounds" ); |
275 | Range range{{*rbegin, *rend, rstep}}; |
276 | |
277 | auto &tds = std::get<parser::TypeDeclarationStmt>(inp.t); |
278 | auto &entities = std::get<std::list<parser::EntityDecl>>(tds.t); |
279 | for (const parser::EntityDecl &ed : entities) { |
280 | auto &name = std::get<parser::ObjectName>(ed.t); |
281 | assert(name.symbol && "Expecting symbol for iterator variable" ); |
282 | auto *stype = name.symbol->GetType(); |
283 | assert(stype && "Expecting symbol type" ); |
284 | IteratorSpecifier spec{{evaluate::DynamicType::From(*stype), |
285 | makeObject(name, semaCtx), range}}; |
286 | specifiers.emplace_back(std::move(spec)); |
287 | } |
288 | |
289 | return specifiers; |
290 | } |
291 | |
292 | Iterator makeIterator(const parser::OmpIterator &inp, |
293 | semantics::SemanticsContext &semaCtx) { |
294 | Iterator iterator; |
295 | for (auto &&spec : inp.v) |
296 | llvm::append_range(iterator, makeIteratorSpecifiers(spec, semaCtx)); |
297 | return iterator; |
298 | } |
299 | |
300 | DefinedOperator makeDefinedOperator(const parser::DefinedOperator &inp, |
301 | semantics::SemanticsContext &semaCtx) { |
302 | CLAUSET_ENUM_CONVERT( // |
303 | convert, parser::DefinedOperator::IntrinsicOperator, |
304 | DefinedOperator::IntrinsicOperator, |
305 | // clang-format off |
306 | MS(Add, Add) |
307 | MS(AND, AND) |
308 | MS(Concat, Concat) |
309 | MS(Divide, Divide) |
310 | MS(EQ, EQ) |
311 | MS(EQV, EQV) |
312 | MS(GE, GE) |
313 | MS(GT, GT) |
314 | MS(NOT, NOT) |
315 | MS(LE, LE) |
316 | MS(LT, LT) |
317 | MS(Multiply, Multiply) |
318 | MS(NE, NE) |
319 | MS(NEQV, NEQV) |
320 | MS(OR, OR) |
321 | MS(Power, Power) |
322 | MS(Subtract, Subtract) |
323 | // clang-format on |
324 | ); |
325 | |
326 | return Fortran::common::visit( |
327 | common::visitors{ |
328 | [&](const parser::DefinedOpName &s) { |
329 | return DefinedOperator{ |
330 | DefinedOperator::DefinedOpName{makeObject(s.v, semaCtx)}}; |
331 | }, |
332 | [&](const parser::DefinedOperator::IntrinsicOperator &s) { |
333 | return DefinedOperator{convert(s)}; |
334 | }, |
335 | }, |
336 | inp.u); |
337 | } |
338 | |
339 | ProcedureDesignator |
340 | makeProcedureDesignator(const parser::ProcedureDesignator &inp, |
341 | semantics::SemanticsContext &semaCtx) { |
342 | return ProcedureDesignator{Fortran::common::visit( |
343 | common::visitors{ |
344 | [&](const parser::Name &t) { return makeObject(t, semaCtx); }, |
345 | [&](const parser::ProcComponentRef &t) { |
346 | return makeObject(t.v.thing, semaCtx); |
347 | }, |
348 | }, |
349 | inp.u)}; |
350 | } |
351 | |
352 | ReductionOperator |
353 | makeReductionOperator(const parser::OmpReductionIdentifier &inp, |
354 | semantics::SemanticsContext &semaCtx) { |
355 | return Fortran::common::visit( |
356 | common::visitors{ |
357 | [&](const parser::DefinedOperator &s) { |
358 | return ReductionOperator{makeDefinedOperator(s, semaCtx)}; |
359 | }, |
360 | [&](const parser::ProcedureDesignator &s) { |
361 | return ReductionOperator{makeProcedureDesignator(s, semaCtx)}; |
362 | }, |
363 | }, |
364 | inp.u); |
365 | } |
366 | |
367 | clause::DependenceType makeDepType(const parser::OmpDependenceType &inp) { |
368 | switch (inp.v) { |
369 | case parser::OmpDependenceType::Value::Sink: |
370 | return clause::DependenceType::Sink; |
371 | case parser::OmpDependenceType::Value::Source: |
372 | return clause::DependenceType::Source; |
373 | } |
374 | llvm_unreachable("Unexpected dependence type" ); |
375 | } |
376 | |
377 | clause::DependenceType makeDepType(const parser::OmpTaskDependenceType &inp) { |
378 | switch (inp.v) { |
379 | case parser::OmpTaskDependenceType::Value::Depobj: |
380 | return clause::DependenceType::Depobj; |
381 | case parser::OmpTaskDependenceType::Value::In: |
382 | return clause::DependenceType::In; |
383 | case parser::OmpTaskDependenceType::Value::Inout: |
384 | return clause::DependenceType::Inout; |
385 | case parser::OmpTaskDependenceType::Value::Inoutset: |
386 | return clause::DependenceType::Inoutset; |
387 | case parser::OmpTaskDependenceType::Value::Mutexinoutset: |
388 | return clause::DependenceType::Mutexinoutset; |
389 | case parser::OmpTaskDependenceType::Value::Out: |
390 | return clause::DependenceType::Out; |
391 | } |
392 | llvm_unreachable("Unexpected task dependence type" ); |
393 | } |
394 | |
395 | clause::Prescriptiveness |
396 | makePrescriptiveness(parser::OmpPrescriptiveness::Value v) { |
397 | switch (v) { |
398 | case parser::OmpPrescriptiveness::Value::Strict: |
399 | return clause::Prescriptiveness::Strict; |
400 | } |
401 | llvm_unreachable("Unexpected prescriptiveness" ); |
402 | } |
403 | |
404 | // -------------------------------------------------------------------- |
405 | // Actual clauses. Each T (where tomp::T exists in ClauseT) has its "make". |
406 | |
407 | Absent make(const parser::OmpClause::Absent &inp, |
408 | semantics::SemanticsContext &semaCtx) { |
409 | llvm_unreachable("Unimplemented: absent" ); |
410 | } |
411 | |
412 | // AcqRel: empty |
413 | // Acquire: empty |
414 | // AdjustArgs: incomplete |
415 | |
416 | Affinity make(const parser::OmpClause::Affinity &inp, |
417 | semantics::SemanticsContext &semaCtx) { |
418 | // inp.v -> parser::OmpAffinityClause |
419 | auto &mods = semantics::OmpGetModifiers(inp.v); |
420 | auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods); |
421 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
422 | |
423 | auto &&maybeIter = |
424 | m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{}; |
425 | |
426 | return Affinity{{/*Iterator=*/std::move(maybeIter), |
427 | /*LocatorList=*/makeObjects(t1, semaCtx)}}; |
428 | } |
429 | |
430 | Align make(const parser::OmpClause::Align &inp, |
431 | semantics::SemanticsContext &semaCtx) { |
432 | // inp -> empty |
433 | llvm_unreachable("Empty: align" ); |
434 | } |
435 | |
436 | Aligned make(const parser::OmpClause::Aligned &inp, |
437 | semantics::SemanticsContext &semaCtx) { |
438 | // inp.v -> parser::OmpAlignedClause |
439 | auto &mods = semantics::OmpGetModifiers(inp.v); |
440 | auto &t0 = std::get<parser::OmpObjectList>(inp.v.t); |
441 | auto *m1 = semantics::OmpGetUniqueModifier<parser::OmpAlignment>(mods); |
442 | |
443 | return Aligned{{ |
444 | /*Alignment=*/maybeApplyToV(makeExprFn(semaCtx), m1), |
445 | /*List=*/makeObjects(t0, semaCtx), |
446 | }}; |
447 | } |
448 | |
449 | Allocate make(const parser::OmpClause::Allocate &inp, |
450 | semantics::SemanticsContext &semaCtx) { |
451 | // inp.v -> parser::OmpAllocateClause |
452 | auto &mods = semantics::OmpGetModifiers(inp.v); |
453 | auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpAlignModifier>(mods); |
454 | auto *m1 = |
455 | semantics::OmpGetUniqueModifier<parser::OmpAllocatorComplexModifier>( |
456 | mods); |
457 | auto *m2 = |
458 | semantics::OmpGetUniqueModifier<parser::OmpAllocatorSimpleModifier>(mods); |
459 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
460 | |
461 | auto makeAllocator = [&](auto *mod) -> std::optional<Allocator> { |
462 | if (mod) |
463 | return Allocator{makeExpr(mod->v, semaCtx)}; |
464 | return std::nullopt; |
465 | }; |
466 | |
467 | auto makeAlign = [&](const parser::ScalarIntExpr &expr) { |
468 | return Align{makeExpr(expr, semaCtx)}; |
469 | }; |
470 | |
471 | auto maybeAllocator = m1 ? makeAllocator(m1) : makeAllocator(m2); |
472 | return Allocate{{/*AllocatorComplexModifier=*/std::move(maybeAllocator), |
473 | /*AlignModifier=*/maybeApplyToV(makeAlign, m0), |
474 | /*List=*/makeObjects(t1, semaCtx)}}; |
475 | } |
476 | |
477 | Allocator make(const parser::OmpClause::Allocator &inp, |
478 | semantics::SemanticsContext &semaCtx) { |
479 | // inp.v -> parser::ScalarIntExpr |
480 | return Allocator{/*Allocator=*/makeExpr(inp.v, semaCtx)}; |
481 | } |
482 | |
483 | // AppendArgs: incomplete |
484 | |
485 | At make(const parser::OmpClause::At &inp, |
486 | semantics::SemanticsContext &semaCtx) { |
487 | // inp -> empty |
488 | llvm_unreachable("Empty: at" ); |
489 | } |
490 | |
491 | // Never called, but needed for using "make" as a Clause visitor. |
492 | // See comment about "requires" clauses in Clauses.h. |
493 | AtomicDefaultMemOrder make(const parser::OmpClause::AtomicDefaultMemOrder &inp, |
494 | semantics::SemanticsContext &semaCtx) { |
495 | // inp.v -> parser::OmpAtomicDefaultMemOrderClause |
496 | CLAUSET_ENUM_CONVERT( // |
497 | convert, common::OmpMemoryOrderType, AtomicDefaultMemOrder::MemoryOrder, |
498 | // clang-format off |
499 | MS(Acq_Rel, AcqRel) |
500 | MS(Acquire, Acquire) |
501 | MS(Relaxed, Relaxed) |
502 | MS(Release, Release) |
503 | MS(Seq_Cst, SeqCst) |
504 | // clang-format on |
505 | ); |
506 | |
507 | return AtomicDefaultMemOrder{/*MemoryOrder=*/convert(inp.v.v)}; |
508 | } |
509 | |
510 | Bind make(const parser::OmpClause::Bind &inp, |
511 | semantics::SemanticsContext &semaCtx) { |
512 | // inp.v -> parser::OmpBindClause |
513 | using wrapped = parser::OmpBindClause; |
514 | |
515 | CLAUSET_ENUM_CONVERT( // |
516 | convert, wrapped::Binding, Bind::Binding, |
517 | // clang-format off |
518 | MS(Teams, Teams) |
519 | MS(Parallel, Parallel) |
520 | MS(Thread, Thread) |
521 | // clang-format on |
522 | ); |
523 | |
524 | return Bind{/*Binding=*/convert(inp.v.v)}; |
525 | } |
526 | |
527 | CancellationConstructType |
528 | make(const parser::OmpClause::CancellationConstructType &inp, |
529 | semantics::SemanticsContext &semaCtx) { |
530 | auto name = std::get<parser::OmpDirectiveName>(inp.v.t); |
531 | CLAUSET_ENUM_CONVERT( |
532 | convert, llvm::omp::Directive, llvm::omp::CancellationConstructType, |
533 | // clang-format off |
534 | MS(OMPD_parallel, OMP_CANCELLATION_CONSTRUCT_Parallel) |
535 | MS(OMPD_do, OMP_CANCELLATION_CONSTRUCT_Loop) |
536 | MS(OMPD_sections, OMP_CANCELLATION_CONSTRUCT_Sections) |
537 | MS(OMPD_taskgroup, OMP_CANCELLATION_CONSTRUCT_Taskgroup) |
538 | // clang-format on |
539 | ); |
540 | |
541 | return CancellationConstructType{convert(name.v)}; |
542 | } |
543 | |
544 | // Capture: empty |
545 | |
546 | Collapse make(const parser::OmpClause::Collapse &inp, |
547 | semantics::SemanticsContext &semaCtx) { |
548 | // inp.v -> parser::ScalarIntConstantExpr |
549 | return Collapse{/*N=*/makeExpr(inp.v, semaCtx)}; |
550 | } |
551 | |
552 | // Compare: empty |
553 | |
554 | Contains make(const parser::OmpClause::Contains &inp, |
555 | semantics::SemanticsContext &semaCtx) { |
556 | llvm_unreachable("Unimplemented: contains" ); |
557 | } |
558 | |
559 | Copyin make(const parser::OmpClause::Copyin &inp, |
560 | semantics::SemanticsContext &semaCtx) { |
561 | // inp.v -> parser::OmpObjectList |
562 | return Copyin{/*List=*/makeObjects(inp.v, semaCtx)}; |
563 | } |
564 | |
565 | Copyprivate make(const parser::OmpClause::Copyprivate &inp, |
566 | semantics::SemanticsContext &semaCtx) { |
567 | // inp.v -> parser::OmpObjectList |
568 | return Copyprivate{/*List=*/makeObjects(inp.v, semaCtx)}; |
569 | } |
570 | |
571 | // The Default clause is overloaded in OpenMP 5.0 and 5.1: it can be either |
572 | // a data-sharing clause, or a METADIRECTIVE clause. In the latter case, it |
573 | // has been superseded by the OTHERWISE clause. |
574 | // Disambiguate this in this representation: for the DSA case, create Default, |
575 | // and in the other case create Otherwise. |
576 | Default makeDefault(const parser::OmpClause::Default &inp, |
577 | semantics::SemanticsContext &semaCtx) { |
578 | // inp.v -> parser::OmpDefaultClause |
579 | using wrapped = parser::OmpDefaultClause; |
580 | |
581 | CLAUSET_ENUM_CONVERT( // |
582 | convert, wrapped::DataSharingAttribute, Default::DataSharingAttribute, |
583 | // clang-format off |
584 | MS(Firstprivate, Firstprivate) |
585 | MS(None, None) |
586 | MS(Private, Private) |
587 | MS(Shared, Shared) |
588 | // clang-format on |
589 | ); |
590 | |
591 | auto dsa = std::get<wrapped::DataSharingAttribute>(inp.v.u); |
592 | return Default{/*DataSharingAttribute=*/convert(dsa)}; |
593 | } |
594 | |
595 | Otherwise makeOtherwise(const parser::OmpClause::Default &inp, |
596 | semantics::SemanticsContext &semaCtx) { |
597 | return Otherwise{}; |
598 | } |
599 | |
600 | Defaultmap make(const parser::OmpClause::Defaultmap &inp, |
601 | semantics::SemanticsContext &semaCtx) { |
602 | // inp.v -> parser::OmpDefaultmapClause |
603 | using wrapped = parser::OmpDefaultmapClause; |
604 | |
605 | CLAUSET_ENUM_CONVERT( // |
606 | convert1, wrapped::ImplicitBehavior, Defaultmap::ImplicitBehavior, |
607 | // clang-format off |
608 | MS(Alloc, Alloc) |
609 | MS(To, To) |
610 | MS(From, From) |
611 | MS(Tofrom, Tofrom) |
612 | MS(Firstprivate, Firstprivate) |
613 | MS(None, None) |
614 | MS(Default, Default) |
615 | MS(Present, Present) |
616 | // clang-format on |
617 | ); |
618 | |
619 | CLAUSET_ENUM_CONVERT( // |
620 | convert2, parser::OmpVariableCategory::Value, |
621 | Defaultmap::VariableCategory, |
622 | // clang-format off |
623 | MS(Aggregate, Aggregate) |
624 | MS(All, All) |
625 | MS(Allocatable, Allocatable) |
626 | MS(Pointer, Pointer) |
627 | MS(Scalar, Scalar) |
628 | // clang-format on |
629 | ); |
630 | |
631 | auto &mods = semantics::OmpGetModifiers(inp.v); |
632 | auto &t0 = std::get<wrapped::ImplicitBehavior>(inp.v.t); |
633 | auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpVariableCategory>(mods); |
634 | |
635 | auto category = t1 ? convert2(t1->v) : Defaultmap::VariableCategory::All; |
636 | return Defaultmap{{/*ImplicitBehavior=*/convert1(t0), |
637 | /*VariableCategory=*/category}}; |
638 | } |
639 | |
640 | Doacross makeDoacross(const parser::OmpDoacross &doa, |
641 | semantics::SemanticsContext &semaCtx) { |
642 | // Iteration is the equivalent of parser::OmpIteration |
643 | using Iteration = Doacross::Vector::value_type; // LoopIterationT |
644 | |
645 | auto visitSource = [&](const parser::OmpDoacross::Source &) { |
646 | return Doacross{{/*DependenceType=*/Doacross::DependenceType::Source, |
647 | /*Vector=*/{}}}; |
648 | }; |
649 | |
650 | auto visitSink = [&](const parser::OmpDoacross::Sink &s) { |
651 | using IterOffset = parser::OmpIterationOffset; |
652 | auto convert2 = [&](const parser::OmpIteration &v) { |
653 | auto &t0 = std::get<parser::Name>(v.t); |
654 | auto &t1 = std::get<std::optional<IterOffset>>(v.t); |
655 | |
656 | auto convert3 = [&](const IterOffset &u) { |
657 | auto &s0 = std::get<parser::DefinedOperator>(u.t); |
658 | auto &s1 = std::get<parser::ScalarIntConstantExpr>(u.t); |
659 | return Iteration::Distance{ |
660 | {makeDefinedOperator(s0, semaCtx), makeExpr(s1, semaCtx)}}; |
661 | }; |
662 | return Iteration{{makeObject(t0, semaCtx), maybeApply(convert3, t1)}}; |
663 | }; |
664 | return Doacross{{/*DependenceType=*/Doacross::DependenceType::Sink, |
665 | /*Vector=*/makeList(s.v.v, convert2)}}; |
666 | }; |
667 | |
668 | return common::visit(common::visitors{visitSink, visitSource}, doa.u); |
669 | } |
670 | |
671 | Depend make(const parser::OmpClause::Depend &inp, |
672 | semantics::SemanticsContext &semaCtx) { |
673 | // inp.v -> parser::OmpDependClause |
674 | using wrapped = parser::OmpDependClause; |
675 | using Variant = decltype(Depend::u); |
676 | |
677 | auto visitTaskDep = [&](const wrapped::TaskDep &s) -> Variant { |
678 | auto &mods = semantics::OmpGetModifiers(s); |
679 | auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods); |
680 | auto *m1 = |
681 | semantics::OmpGetUniqueModifier<parser::OmpTaskDependenceType>(mods); |
682 | auto &t1 = std::get<parser::OmpObjectList>(s.t); |
683 | assert(m1 && "expecting task dependence type" ); |
684 | |
685 | auto &&maybeIter = |
686 | m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{}; |
687 | return Depend::TaskDep{{/*DependenceType=*/makeDepType(*m1), |
688 | /*Iterator=*/std::move(maybeIter), |
689 | /*LocatorList=*/makeObjects(t1, semaCtx)}}; |
690 | }; |
691 | |
692 | return Depend{common::visit( // |
693 | common::visitors{ |
694 | // Doacross |
695 | [&](const parser::OmpDoacross &s) -> Variant { |
696 | return makeDoacross(s, semaCtx); |
697 | }, |
698 | // Depend::TaskDep |
699 | visitTaskDep, |
700 | }, |
701 | inp.v.u)}; |
702 | } |
703 | |
704 | // Depobj: empty |
705 | |
706 | Destroy make(const parser::OmpClause::Destroy &inp, |
707 | semantics::SemanticsContext &semaCtx) { |
708 | // inp.v -> std::optional<OmpDestroyClause> |
709 | auto &&maybeObject = maybeApply( |
710 | [&](const parser::OmpDestroyClause &c) { |
711 | return makeObject(c.v, semaCtx); |
712 | }, |
713 | inp.v); |
714 | |
715 | return Destroy{/*DestroyVar=*/std::move(maybeObject)}; |
716 | } |
717 | |
718 | Detach make(const parser::OmpClause::Detach &inp, |
719 | semantics::SemanticsContext &semaCtx) { |
720 | // inp.v -> parser::OmpDetachClause |
721 | return Detach{makeObject(inp.v.v, semaCtx)}; |
722 | } |
723 | |
724 | Device make(const parser::OmpClause::Device &inp, |
725 | semantics::SemanticsContext &semaCtx) { |
726 | // inp.v -> parser::OmpDeviceClause |
727 | CLAUSET_ENUM_CONVERT( // |
728 | convert, parser::OmpDeviceModifier::Value, Device::DeviceModifier, |
729 | // clang-format off |
730 | MS(Ancestor, Ancestor) |
731 | MS(Device_Num, DeviceNum) |
732 | // clang-format on |
733 | ); |
734 | |
735 | auto &mods = semantics::OmpGetModifiers(inp.v); |
736 | auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpDeviceModifier>(mods); |
737 | auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t); |
738 | return Device{{/*DeviceModifier=*/maybeApplyToV(convert, m0), |
739 | /*DeviceDescription=*/makeExpr(t1, semaCtx)}}; |
740 | } |
741 | |
742 | DeviceType make(const parser::OmpClause::DeviceType &inp, |
743 | semantics::SemanticsContext &semaCtx) { |
744 | // inp.v -> parser::OmpDeviceTypeClause |
745 | using wrapped = parser::OmpDeviceTypeClause; |
746 | |
747 | CLAUSET_ENUM_CONVERT( // |
748 | convert, wrapped::DeviceTypeDescription, |
749 | DeviceType::DeviceTypeDescription, |
750 | // clang-format off |
751 | MS(Any, Any) |
752 | MS(Host, Host) |
753 | MS(Nohost, Nohost) |
754 | // clang-format om |
755 | ); |
756 | return DeviceType{/*DeviceTypeDescription=*/convert(inp.v.v)}; |
757 | } |
758 | |
759 | DistSchedule make(const parser::OmpClause::DistSchedule &inp, |
760 | semantics::SemanticsContext &semaCtx) { |
761 | // inp.v -> std::optional<parser::ScalarIntExpr> |
762 | return DistSchedule{{/*Kind=*/DistSchedule::Kind::Static, |
763 | /*ChunkSize=*/maybeApply(makeExprFn(semaCtx), inp.v)}}; |
764 | } |
765 | |
766 | Doacross make(const parser::OmpClause::Doacross &inp, |
767 | semantics::SemanticsContext &semaCtx) { |
768 | // inp.v -> OmpDoacrossClause |
769 | return makeDoacross(inp.v.v, semaCtx); |
770 | } |
771 | |
772 | // DynamicAllocators: empty |
773 | |
774 | Enter make(const parser::OmpClause::Enter &inp, |
775 | semantics::SemanticsContext &semaCtx) { |
776 | // inp.v -> parser::OmpObjectList |
777 | return Enter{makeObjects(/*List=*/inp.v, semaCtx)}; |
778 | } |
779 | |
780 | Exclusive make(const parser::OmpClause::Exclusive &inp, |
781 | semantics::SemanticsContext &semaCtx) { |
782 | // inp.v -> parser::OmpObjectList |
783 | return Exclusive{makeObjects(/*List=*/inp.v, semaCtx)}; |
784 | } |
785 | |
786 | Fail make(const parser::OmpClause::Fail &inp, |
787 | semantics::SemanticsContext &semaCtx) { |
788 | // inp.v -> parser::OmpFalClause |
789 | CLAUSET_ENUM_CONVERT( // |
790 | convert, common::OmpMemoryOrderType, Fail::MemoryOrder, |
791 | // clang-format off |
792 | MS(Acq_Rel, AcqRel) |
793 | MS(Acquire, Acquire) |
794 | MS(Relaxed, Relaxed) |
795 | MS(Release, Release) |
796 | MS(Seq_Cst, SeqCst) |
797 | // clang-format on |
798 | ); |
799 | |
800 | return Fail{/*MemoryOrder=*/convert(inp.v.v)}; |
801 | } |
802 | |
803 | Filter make(const parser::OmpClause::Filter &inp, |
804 | semantics::SemanticsContext &semaCtx) { |
805 | // inp.v -> parser::ScalarIntExpr |
806 | return Filter{/*ThreadNum=*/makeExpr(inp.v, semaCtx)}; |
807 | } |
808 | |
809 | Final make(const parser::OmpClause::Final &inp, |
810 | semantics::SemanticsContext &semaCtx) { |
811 | // inp.v -> parser::ScalarLogicalExpr |
812 | return Final{/*Finalize=*/makeExpr(inp.v, semaCtx)}; |
813 | } |
814 | |
815 | Firstprivate make(const parser::OmpClause::Firstprivate &inp, |
816 | semantics::SemanticsContext &semaCtx) { |
817 | // inp.v -> parser::OmpObjectList |
818 | return Firstprivate{/*List=*/makeObjects(inp.v, semaCtx)}; |
819 | } |
820 | |
821 | // Flush: empty |
822 | |
823 | From make(const parser::OmpClause::From &inp, |
824 | semantics::SemanticsContext &semaCtx) { |
825 | // inp.v -> parser::OmpFromClause |
826 | CLAUSET_ENUM_CONVERT( // |
827 | convert, parser::OmpExpectation::Value, From::Expectation, |
828 | // clang-format off |
829 | MS(Present, Present) |
830 | // clang-format on |
831 | ); |
832 | |
833 | auto &mods = semantics::OmpGetModifiers(inp.v); |
834 | auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods); |
835 | auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods); |
836 | auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods); |
837 | auto &t3 = std::get<parser::OmpObjectList>(inp.v.t); |
838 | |
839 | auto mappers = [&]() -> std::optional<List<Mapper>> { |
840 | if (t1) |
841 | return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}}; |
842 | return std::nullopt; |
843 | }(); |
844 | |
845 | auto iterator = [&]() -> std::optional<Iterator> { |
846 | if (t2) |
847 | return makeIterator(*t2, semaCtx); |
848 | return std::nullopt; |
849 | }(); |
850 | |
851 | return From{{/*Expectation=*/maybeApplyToV(convert, t0), |
852 | /*Mappers=*/std::move(mappers), |
853 | /*Iterator=*/std::move(iterator), |
854 | /*LocatorList=*/makeObjects(t3, semaCtx)}}; |
855 | } |
856 | |
857 | // Full: empty |
858 | |
859 | Grainsize make(const parser::OmpClause::Grainsize &inp, |
860 | semantics::SemanticsContext &semaCtx) { |
861 | // inp.v -> parser::OmpGrainsizeClause |
862 | auto &mods = semantics::OmpGetModifiers(inp.v); |
863 | auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpPrescriptiveness>(mods); |
864 | auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t); |
865 | return Grainsize{ |
866 | {/*Prescriptiveness=*/maybeApplyToV(makePrescriptiveness, m0), |
867 | /*Grainsize=*/makeExpr(t1, semaCtx)}}; |
868 | } |
869 | |
870 | HasDeviceAddr make(const parser::OmpClause::HasDeviceAddr &inp, |
871 | semantics::SemanticsContext &semaCtx) { |
872 | // inp.v -> parser::OmpObjectList |
873 | return HasDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)}; |
874 | } |
875 | |
876 | Hint make(const parser::OmpClause::Hint &inp, |
877 | semantics::SemanticsContext &semaCtx) { |
878 | // inp.v -> parser::OmpHintClause |
879 | return Hint{/*HintExpr=*/makeExpr(inp.v.v, semaCtx)}; |
880 | } |
881 | |
882 | Holds make(const parser::OmpClause::Holds &inp, |
883 | semantics::SemanticsContext &semaCtx) { |
884 | llvm_unreachable("Unimplemented: holds" ); |
885 | } |
886 | |
887 | If make(const parser::OmpClause::If &inp, |
888 | semantics::SemanticsContext &semaCtx) { |
889 | // inp.v -> parser::OmpIfClause |
890 | auto &mods = semantics::OmpGetModifiers(inp.v); |
891 | auto *m0 = |
892 | semantics::OmpGetUniqueModifier<parser::OmpDirectiveNameModifier>(mods); |
893 | auto &t1 = std::get<parser::ScalarLogicalExpr>(inp.v.t); |
894 | return If{ |
895 | {/*DirectiveNameModifier=*/maybeApplyToV([](auto &&s) { return s; }, m0), |
896 | /*IfExpression=*/makeExpr(t1, semaCtx)}}; |
897 | } |
898 | |
899 | // Inbranch: empty |
900 | |
901 | Inclusive make(const parser::OmpClause::Inclusive &inp, |
902 | semantics::SemanticsContext &semaCtx) { |
903 | // inp.v -> parser::OmpObjectList |
904 | return Inclusive{makeObjects(/*List=*/inp.v, semaCtx)}; |
905 | } |
906 | |
907 | Indirect make(const parser::OmpClause::Indirect &inp, |
908 | semantics::SemanticsContext &semaCtx) { |
909 | // inp -> empty |
910 | llvm_unreachable("Empty: indirect" ); |
911 | } |
912 | |
913 | Init make(const parser::OmpClause::Init &inp, |
914 | semantics::SemanticsContext &semaCtx) { |
915 | // inp -> empty |
916 | llvm_unreachable("Empty: init" ); |
917 | } |
918 | |
919 | Initializer make(const parser::OmpClause::Initializer &inp, |
920 | semantics::SemanticsContext &semaCtx) { |
921 | llvm_unreachable("Empty: initializer" ); |
922 | } |
923 | |
924 | InReduction make(const parser::OmpClause::InReduction &inp, |
925 | semantics::SemanticsContext &semaCtx) { |
926 | // inp.v -> parser::OmpInReductionClause |
927 | auto &mods = semantics::OmpGetModifiers(inp.v); |
928 | auto *m0 = |
929 | semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods); |
930 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
931 | assert(m0 && "OmpReductionIdentifier is required" ); |
932 | |
933 | return InReduction{ |
934 | {/*ReductionIdentifiers=*/{makeReductionOperator(*m0, semaCtx)}, |
935 | /*List=*/makeObjects(t1, semaCtx)}}; |
936 | } |
937 | |
938 | IsDevicePtr make(const parser::OmpClause::IsDevicePtr &inp, |
939 | semantics::SemanticsContext &semaCtx) { |
940 | // inp.v -> parser::OmpObjectList |
941 | return IsDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)}; |
942 | } |
943 | |
944 | Lastprivate make(const parser::OmpClause::Lastprivate &inp, |
945 | semantics::SemanticsContext &semaCtx) { |
946 | // inp.v -> parser::OmpLastprivateClause |
947 | CLAUSET_ENUM_CONVERT( // |
948 | convert, parser::OmpLastprivateModifier::Value, |
949 | Lastprivate::LastprivateModifier, |
950 | // clang-format off |
951 | MS(Conditional, Conditional) |
952 | // clang-format on |
953 | ); |
954 | |
955 | auto &mods = semantics::OmpGetModifiers(inp.v); |
956 | auto *m0 = |
957 | semantics::OmpGetUniqueModifier<parser::OmpLastprivateModifier>(mods); |
958 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
959 | |
960 | return Lastprivate{{/*LastprivateModifier=*/maybeApplyToV(convert, m0), |
961 | /*List=*/makeObjects(t1, semaCtx)}}; |
962 | } |
963 | |
964 | Linear make(const parser::OmpClause::Linear &inp, |
965 | semantics::SemanticsContext &semaCtx) { |
966 | // inp.v -> parser::OmpLinearClause |
967 | CLAUSET_ENUM_CONVERT( // |
968 | convert, parser::OmpLinearModifier::Value, Linear::LinearModifier, |
969 | // clang-format off |
970 | MS(Ref, Ref) |
971 | MS(Val, Val) |
972 | MS(Uval, Uval) |
973 | // clang-format on |
974 | ); |
975 | |
976 | auto &mods = semantics::OmpGetModifiers(inp.v); |
977 | auto *m0 = |
978 | semantics::OmpGetUniqueModifier<parser::OmpStepComplexModifier>(mods); |
979 | auto *m1 = |
980 | semantics::OmpGetUniqueModifier<parser::OmpStepSimpleModifier>(mods); |
981 | assert((!m0 || !m1) && "Simple and complex modifiers both present" ); |
982 | |
983 | auto *m2 = semantics::OmpGetUniqueModifier<parser::OmpLinearModifier>(mods); |
984 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
985 | |
986 | auto &&maybeStep = m0 ? maybeApplyToV(makeExprFn(semaCtx), m0) |
987 | : m1 ? maybeApplyToV(makeExprFn(semaCtx), m1) |
988 | : std::optional<Linear::StepComplexModifier>{}; |
989 | |
990 | return Linear{{/*StepComplexModifier=*/std::move(maybeStep), |
991 | /*LinearModifier=*/maybeApplyToV(convert, m2), |
992 | /*List=*/makeObjects(t1, semaCtx)}}; |
993 | } |
994 | |
995 | Link make(const parser::OmpClause::Link &inp, |
996 | semantics::SemanticsContext &semaCtx) { |
997 | // inp.v -> parser::OmpObjectList |
998 | return Link{/*List=*/makeObjects(inp.v, semaCtx)}; |
999 | } |
1000 | |
1001 | Map make(const parser::OmpClause::Map &inp, |
1002 | semantics::SemanticsContext &semaCtx) { |
1003 | // inp.v -> parser::OmpMapClause |
1004 | CLAUSET_ENUM_CONVERT( // |
1005 | convert1, parser::OmpMapType::Value, Map::MapType, |
1006 | // clang-format off |
1007 | MS(Alloc, Alloc) |
1008 | MS(Delete, Delete) |
1009 | MS(From, From) |
1010 | MS(Release, Release) |
1011 | MS(To, To) |
1012 | MS(Tofrom, Tofrom) |
1013 | // clang-format on |
1014 | ); |
1015 | |
1016 | CLAUSET_ENUM_CONVERT( // |
1017 | convert2, parser::OmpMapTypeModifier::Value, Map::MapTypeModifier, |
1018 | // clang-format off |
1019 | MS(Always, Always) |
1020 | MS(Close, Close) |
1021 | MS(Ompx_Hold, OmpxHold) |
1022 | MS(Present, Present) |
1023 | // clang-format on |
1024 | ); |
1025 | |
1026 | auto &mods = semantics::OmpGetModifiers(inp.v); |
1027 | auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods); |
1028 | auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods); |
1029 | auto *t3 = semantics::OmpGetUniqueModifier<parser::OmpMapType>(mods); |
1030 | auto &t4 = std::get<parser::OmpObjectList>(inp.v.t); |
1031 | |
1032 | auto mappers = [&]() -> std::optional<List<Mapper>> { |
1033 | if (t1) |
1034 | return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}}; |
1035 | return std::nullopt; |
1036 | }(); |
1037 | |
1038 | auto iterator = [&]() -> std::optional<Iterator> { |
1039 | if (t2) |
1040 | return makeIterator(*t2, semaCtx); |
1041 | return std::nullopt; |
1042 | }(); |
1043 | |
1044 | auto type = [&]() -> std::optional<Map::MapType> { |
1045 | if (t3) |
1046 | return convert1(t3->v); |
1047 | return Map::MapType::Tofrom; |
1048 | }(); |
1049 | |
1050 | Map::MapTypeModifiers typeMods; |
1051 | for (auto *typeMod : |
1052 | semantics::OmpGetRepeatableModifier<parser::OmpMapTypeModifier>(mods)) { |
1053 | typeMods.push_back(convert2(typeMod->v)); |
1054 | } |
1055 | std::optional<Map::MapTypeModifiers> maybeTypeMods{}; |
1056 | if (!typeMods.empty()) |
1057 | maybeTypeMods = std::move(typeMods); |
1058 | |
1059 | return Map{{/*MapType=*/std::move(type), |
1060 | /*MapTypeModifiers=*/std::move(maybeTypeMods), |
1061 | /*Mapper=*/std::move(mappers), /*Iterator=*/std::move(iterator), |
1062 | /*LocatorList=*/makeObjects(t4, semaCtx)}}; |
1063 | } |
1064 | |
1065 | Match make(const parser::OmpClause::Match &inp, |
1066 | semantics::SemanticsContext &semaCtx) { |
1067 | return Match{}; |
1068 | } |
1069 | |
1070 | // MemoryOrder: empty |
1071 | // Mergeable: empty |
1072 | |
1073 | Message make(const parser::OmpClause::Message &inp, |
1074 | semantics::SemanticsContext &semaCtx) { |
1075 | // inp -> empty |
1076 | llvm_unreachable("Empty: message" ); |
1077 | } |
1078 | |
1079 | Nocontext make(const parser::OmpClause::Nocontext &inp, |
1080 | semantics::SemanticsContext &semaCtx) { |
1081 | // inp.v -> parser::ScalarLogicalExpr |
1082 | return Nocontext{/*DoNotUpdateContext=*/makeExpr(inp.v, semaCtx)}; |
1083 | } |
1084 | |
1085 | // Nogroup: empty |
1086 | |
1087 | Nontemporal make(const parser::OmpClause::Nontemporal &inp, |
1088 | semantics::SemanticsContext &semaCtx) { |
1089 | // inp.v -> std::list<parser::Name> |
1090 | return Nontemporal{/*List=*/makeList(inp.v, makeObjectFn(semaCtx))}; |
1091 | } |
1092 | |
1093 | // NoOpenmp: empty |
1094 | // NoOpenmpRoutines: empty |
1095 | // NoOpenmpConstructs: empty |
1096 | // NoParallelism: empty |
1097 | // Notinbranch: empty |
1098 | |
1099 | Novariants make(const parser::OmpClause::Novariants &inp, |
1100 | semantics::SemanticsContext &semaCtx) { |
1101 | // inp.v -> parser::ScalarLogicalExpr |
1102 | return Novariants{/*DoNotUseVariant=*/makeExpr(inp.v, semaCtx)}; |
1103 | } |
1104 | |
1105 | // Nowait: empty |
1106 | |
1107 | NumTasks make(const parser::OmpClause::NumTasks &inp, |
1108 | semantics::SemanticsContext &semaCtx) { |
1109 | // inp.v -> parser::OmpNumTasksClause |
1110 | auto &mods = semantics::OmpGetModifiers(inp.v); |
1111 | auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpPrescriptiveness>(mods); |
1112 | auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t); |
1113 | return NumTasks{{/*Prescriptiveness=*/maybeApplyToV(makePrescriptiveness, m0), |
1114 | /*NumTasks=*/makeExpr(t1, semaCtx)}}; |
1115 | } |
1116 | |
1117 | NumTeams make(const parser::OmpClause::NumTeams &inp, |
1118 | semantics::SemanticsContext &semaCtx) { |
1119 | // inp.v -> parser::ScalarIntExpr |
1120 | List<NumTeams::Range> v{{{/*LowerBound=*/std::nullopt, |
1121 | /*UpperBound=*/makeExpr(inp.v, semaCtx)}}}; |
1122 | return NumTeams{/*List=*/v}; |
1123 | } |
1124 | |
1125 | NumThreads make(const parser::OmpClause::NumThreads &inp, |
1126 | semantics::SemanticsContext &semaCtx) { |
1127 | // inp.v -> parser::ScalarIntExpr |
1128 | return NumThreads{/*Nthreads=*/makeExpr(inp.v, semaCtx)}; |
1129 | } |
1130 | |
1131 | // OmpxAttribute: empty |
1132 | // OmpxBare: empty |
1133 | |
1134 | OmpxDynCgroupMem make(const parser::OmpClause::OmpxDynCgroupMem &inp, |
1135 | semantics::SemanticsContext &semaCtx) { |
1136 | // inp.v -> parser::ScalarIntExpr |
1137 | return OmpxDynCgroupMem{makeExpr(inp.v, semaCtx)}; |
1138 | } |
1139 | |
1140 | Order make(const parser::OmpClause::Order &inp, |
1141 | semantics::SemanticsContext &semaCtx) { |
1142 | // inp.v -> parser::OmpOrderClause |
1143 | using wrapped = parser::OmpOrderClause; |
1144 | |
1145 | CLAUSET_ENUM_CONVERT( // |
1146 | convert1, parser::OmpOrderModifier::Value, Order::OrderModifier, |
1147 | // clang-format off |
1148 | MS(Reproducible, Reproducible) |
1149 | MS(Unconstrained, Unconstrained) |
1150 | // clang-format on |
1151 | ); |
1152 | |
1153 | CLAUSET_ENUM_CONVERT( // |
1154 | convert2, wrapped::Ordering, Order::Ordering, |
1155 | // clang-format off |
1156 | MS(Concurrent, Concurrent) |
1157 | // clang-format on |
1158 | ); |
1159 | |
1160 | auto &mods = semantics::OmpGetModifiers(inp.v); |
1161 | auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpOrderModifier>(mods); |
1162 | auto &t1 = std::get<wrapped::Ordering>(inp.v.t); |
1163 | |
1164 | return Order{{/*OrderModifier=*/maybeApplyToV(convert1, t0), |
1165 | /*Ordering=*/convert2(t1)}}; |
1166 | } |
1167 | |
1168 | Ordered make(const parser::OmpClause::Ordered &inp, |
1169 | semantics::SemanticsContext &semaCtx) { |
1170 | // inp.v -> std::optional<parser::ScalarIntConstantExpr> |
1171 | return Ordered{/*N=*/maybeApply(makeExprFn(semaCtx), inp.v)}; |
1172 | } |
1173 | |
1174 | // See also Default. |
1175 | Otherwise make(const parser::OmpClause::Otherwise &inp, |
1176 | semantics::SemanticsContext &semaCtx) { |
1177 | return Otherwise{}; |
1178 | } |
1179 | |
1180 | Partial make(const parser::OmpClause::Partial &inp, |
1181 | semantics::SemanticsContext &semaCtx) { |
1182 | // inp.v -> std::optional<parser::ScalarIntConstantExpr> |
1183 | return Partial{/*UnrollFactor=*/maybeApply(makeExprFn(semaCtx), inp.v)}; |
1184 | } |
1185 | |
1186 | Priority make(const parser::OmpClause::Priority &inp, |
1187 | semantics::SemanticsContext &semaCtx) { |
1188 | // inp.v -> parser::ScalarIntExpr |
1189 | return Priority{/*PriorityValue=*/makeExpr(inp.v, semaCtx)}; |
1190 | } |
1191 | |
1192 | Private make(const parser::OmpClause::Private &inp, |
1193 | semantics::SemanticsContext &semaCtx) { |
1194 | // inp.v -> parser::OmpObjectList |
1195 | return Private{/*List=*/makeObjects(inp.v, semaCtx)}; |
1196 | } |
1197 | |
1198 | ProcBind make(const parser::OmpClause::ProcBind &inp, |
1199 | semantics::SemanticsContext &semaCtx) { |
1200 | // inp.v -> parser::OmpProcBindClause |
1201 | using wrapped = parser::OmpProcBindClause; |
1202 | |
1203 | CLAUSET_ENUM_CONVERT( // |
1204 | convert, wrapped::AffinityPolicy, ProcBind::AffinityPolicy, |
1205 | // clang-format off |
1206 | MS(Close, Close) |
1207 | MS(Master, Master) |
1208 | MS(Spread, Spread) |
1209 | MS(Primary, Primary) |
1210 | // clang-format on |
1211 | ); |
1212 | return ProcBind{/*AffinityPolicy=*/convert(inp.v.v)}; |
1213 | } |
1214 | |
1215 | // Read: empty |
1216 | |
1217 | Reduction make(const parser::OmpClause::Reduction &inp, |
1218 | semantics::SemanticsContext &semaCtx) { |
1219 | // inp.v -> parser::OmpReductionClause |
1220 | CLAUSET_ENUM_CONVERT( // |
1221 | convert, parser::OmpReductionModifier::Value, |
1222 | Reduction::ReductionModifier, |
1223 | // clang-format off |
1224 | MS(Inscan, Inscan) |
1225 | MS(Task, Task) |
1226 | MS(Default, Default) |
1227 | // clang-format on |
1228 | ); |
1229 | |
1230 | auto &mods = semantics::OmpGetModifiers(inp.v); |
1231 | auto *m0 = |
1232 | semantics::OmpGetUniqueModifier<parser::OmpReductionModifier>(mods); |
1233 | auto *m1 = |
1234 | semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods); |
1235 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
1236 | assert(m1 && "OmpReductionIdentifier is required" ); |
1237 | |
1238 | return Reduction{ |
1239 | {/*ReductionModifier=*/maybeApplyToV(convert, m0), |
1240 | /*ReductionIdentifiers=*/{makeReductionOperator(*m1, semaCtx)}, |
1241 | /*List=*/makeObjects(t1, semaCtx)}}; |
1242 | } |
1243 | |
1244 | // Relaxed: empty |
1245 | // Release: empty |
1246 | // ReverseOffload: empty |
1247 | |
1248 | Safelen make(const parser::OmpClause::Safelen &inp, |
1249 | semantics::SemanticsContext &semaCtx) { |
1250 | // inp.v -> parser::ScalarIntConstantExpr |
1251 | return Safelen{/*Length=*/makeExpr(inp.v, semaCtx)}; |
1252 | } |
1253 | |
1254 | Schedule make(const parser::OmpClause::Schedule &inp, |
1255 | semantics::SemanticsContext &semaCtx) { |
1256 | // inp.v -> parser::OmpScheduleClause |
1257 | using wrapped = parser::OmpScheduleClause; |
1258 | |
1259 | CLAUSET_ENUM_CONVERT( // |
1260 | convert1, wrapped::Kind, Schedule::Kind, |
1261 | // clang-format off |
1262 | MS(Static, Static) |
1263 | MS(Dynamic, Dynamic) |
1264 | MS(Guided, Guided) |
1265 | MS(Auto, Auto) |
1266 | MS(Runtime, Runtime) |
1267 | // clang-format on |
1268 | ); |
1269 | |
1270 | CLAUSET_ENUM_CONVERT( // |
1271 | convert2, parser::OmpOrderingModifier::Value, Schedule::OrderingModifier, |
1272 | // clang-format off |
1273 | MS(Monotonic, Monotonic) |
1274 | MS(Nonmonotonic, Nonmonotonic) |
1275 | // clang-format on |
1276 | ); |
1277 | |
1278 | CLAUSET_ENUM_CONVERT( // |
1279 | convert3, parser::OmpChunkModifier::Value, Schedule::ChunkModifier, |
1280 | // clang-format off |
1281 | MS(Simd, Simd) |
1282 | // clang-format on |
1283 | ); |
1284 | |
1285 | auto &mods = semantics::OmpGetModifiers(inp.v); |
1286 | auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpOrderingModifier>(mods); |
1287 | auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpChunkModifier>(mods); |
1288 | auto &t2 = std::get<wrapped::Kind>(inp.v.t); |
1289 | auto &t3 = std::get<std::optional<parser::ScalarIntExpr>>(inp.v.t); |
1290 | |
1291 | return Schedule{{/*Kind=*/convert1(t2), |
1292 | /*OrderingModifier=*/maybeApplyToV(convert2, t0), |
1293 | /*ChunkModifier=*/maybeApplyToV(convert3, t1), |
1294 | /*ChunkSize=*/maybeApply(makeExprFn(semaCtx), t3)}}; |
1295 | } |
1296 | |
1297 | // SeqCst: empty |
1298 | |
1299 | Severity make(const parser::OmpClause::Severity &inp, |
1300 | semantics::SemanticsContext &semaCtx) { |
1301 | // inp -> empty |
1302 | llvm_unreachable("Empty: severity" ); |
1303 | } |
1304 | |
1305 | Shared make(const parser::OmpClause::Shared &inp, |
1306 | semantics::SemanticsContext &semaCtx) { |
1307 | // inp.v -> parser::OmpObjectList |
1308 | return Shared{/*List=*/makeObjects(inp.v, semaCtx)}; |
1309 | } |
1310 | |
1311 | // Simd: empty |
1312 | |
1313 | Simdlen make(const parser::OmpClause::Simdlen &inp, |
1314 | semantics::SemanticsContext &semaCtx) { |
1315 | // inp.v -> parser::ScalarIntConstantExpr |
1316 | return Simdlen{/*Length=*/makeExpr(inp.v, semaCtx)}; |
1317 | } |
1318 | |
1319 | Sizes make(const parser::OmpClause::Sizes &inp, |
1320 | semantics::SemanticsContext &semaCtx) { |
1321 | // inp.v -> std::list<parser::ScalarIntExpr> |
1322 | return Sizes{/*SizeList=*/makeList(inp.v, makeExprFn(semaCtx))}; |
1323 | } |
1324 | |
1325 | Permutation make(const parser::OmpClause::Permutation &inp, |
1326 | semantics::SemanticsContext &semaCtx) { |
1327 | // inp.v -> std::list<parser::ScalarIntConstantExpr> |
1328 | return Permutation{/*ArgList=*/makeList(inp.v, makeExprFn(semaCtx))}; |
1329 | } |
1330 | |
1331 | TaskReduction make(const parser::OmpClause::TaskReduction &inp, |
1332 | semantics::SemanticsContext &semaCtx) { |
1333 | // inp.v -> parser::OmpReductionClause |
1334 | auto &mods = semantics::OmpGetModifiers(inp.v); |
1335 | auto *m0 = |
1336 | semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods); |
1337 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
1338 | assert(m0 && "OmpReductionIdentifier is required" ); |
1339 | |
1340 | return TaskReduction{ |
1341 | {/*ReductionIdentifiers=*/{makeReductionOperator(*m0, semaCtx)}, |
1342 | /*List=*/makeObjects(t1, semaCtx)}}; |
1343 | } |
1344 | |
1345 | ThreadLimit make(const parser::OmpClause::ThreadLimit &inp, |
1346 | semantics::SemanticsContext &semaCtx) { |
1347 | // inp.v -> parser::ScalarIntExpr |
1348 | return ThreadLimit{/*Threadlim=*/makeExpr(inp.v, semaCtx)}; |
1349 | } |
1350 | |
1351 | // Threadprivate: empty |
1352 | // Threads: empty |
1353 | |
1354 | To make(const parser::OmpClause::To &inp, |
1355 | semantics::SemanticsContext &semaCtx) { |
1356 | // inp.v -> parser::OmpToClause |
1357 | CLAUSET_ENUM_CONVERT( // |
1358 | convert, parser::OmpExpectation::Value, To::Expectation, |
1359 | // clang-format off |
1360 | MS(Present, Present) |
1361 | // clang-format on |
1362 | ); |
1363 | |
1364 | auto &mods = semantics::OmpGetModifiers(inp.v); |
1365 | auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods); |
1366 | auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods); |
1367 | auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods); |
1368 | auto &t3 = std::get<parser::OmpObjectList>(inp.v.t); |
1369 | |
1370 | auto mappers = [&]() -> std::optional<List<Mapper>> { |
1371 | if (t1) |
1372 | return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}}; |
1373 | return std::nullopt; |
1374 | }(); |
1375 | |
1376 | auto iterator = [&]() -> std::optional<Iterator> { |
1377 | if (t2) |
1378 | return makeIterator(*t2, semaCtx); |
1379 | return std::nullopt; |
1380 | }(); |
1381 | |
1382 | return To{{/*Expectation=*/maybeApplyToV(convert, t0), |
1383 | /*Mappers=*/{std::move(mappers)}, |
1384 | /*Iterator=*/std::move(iterator), |
1385 | /*LocatorList=*/makeObjects(t3, semaCtx)}}; |
1386 | } |
1387 | |
1388 | // UnifiedAddress: empty |
1389 | // UnifiedSharedMemory: empty |
1390 | |
1391 | Uniform make(const parser::OmpClause::Uniform &inp, |
1392 | semantics::SemanticsContext &semaCtx) { |
1393 | // inp.v -> std::list<parser::Name> |
1394 | return Uniform{/*ParameterList=*/makeList(inp.v, makeObjectFn(semaCtx))}; |
1395 | } |
1396 | |
1397 | // Unknown: empty |
1398 | // Untied: empty |
1399 | |
1400 | Update make(const parser::OmpClause::Update &inp, |
1401 | semantics::SemanticsContext &semaCtx) { |
1402 | // inp.v -> parser::OmpUpdateClause |
1403 | if (inp.v) { |
1404 | return common::visit( |
1405 | [](auto &&s) { return Update{/*DependenceType=*/makeDepType(s)}; }, |
1406 | inp.v->u); |
1407 | } else { |
1408 | return Update{/*DependenceType=*/std::nullopt}; |
1409 | } |
1410 | } |
1411 | |
1412 | Use make(const parser::OmpClause::Use &inp, |
1413 | semantics::SemanticsContext &semaCtx) { |
1414 | // inp -> empty |
1415 | llvm_unreachable("Empty: use" ); |
1416 | } |
1417 | |
1418 | UseDeviceAddr make(const parser::OmpClause::UseDeviceAddr &inp, |
1419 | semantics::SemanticsContext &semaCtx) { |
1420 | // inp.v -> parser::OmpObjectList |
1421 | return UseDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)}; |
1422 | } |
1423 | |
1424 | UseDevicePtr make(const parser::OmpClause::UseDevicePtr &inp, |
1425 | semantics::SemanticsContext &semaCtx) { |
1426 | // inp.v -> parser::OmpObjectList |
1427 | return UseDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)}; |
1428 | } |
1429 | |
1430 | UsesAllocators make(const parser::OmpClause::UsesAllocators &inp, |
1431 | semantics::SemanticsContext &semaCtx) { |
1432 | // inp -> empty |
1433 | llvm_unreachable("Empty: uses_allocators" ); |
1434 | } |
1435 | |
1436 | // Weak: empty |
1437 | |
1438 | When make(const parser::OmpClause::When &inp, |
1439 | semantics::SemanticsContext &semaCtx) { |
1440 | return When{}; |
1441 | } |
1442 | |
1443 | // Write: empty |
1444 | } // namespace clause |
1445 | |
1446 | Clause makeClause(const parser::OmpClause &cls, |
1447 | semantics::SemanticsContext &semaCtx) { |
1448 | return Fortran::common::visit( // |
1449 | common::visitors{ |
1450 | [&](const parser::OmpClause::Default &s) { |
1451 | using DSA = parser::OmpDefaultClause::DataSharingAttribute; |
1452 | if (std::holds_alternative<DSA>(s.v.u)) { |
1453 | return makeClause(llvm::omp::Clause::OMPC_default, |
1454 | clause::makeDefault(s, semaCtx), cls.source); |
1455 | } else { |
1456 | return makeClause(llvm::omp::Clause::OMPC_otherwise, |
1457 | clause::makeOtherwise(s, semaCtx), cls.source); |
1458 | } |
1459 | }, |
1460 | [&](auto &&s) { |
1461 | return makeClause(cls.Id(), clause::make(s, semaCtx), cls.source); |
1462 | }, |
1463 | }, |
1464 | cls.u); |
1465 | } |
1466 | |
1467 | List<Clause> makeClauses(const parser::OmpClauseList &clauses, |
1468 | semantics::SemanticsContext &semaCtx) { |
1469 | return makeList(clauses.v, [&](const parser::OmpClause &s) { |
1470 | return makeClause(s, semaCtx); |
1471 | }); |
1472 | } |
1473 | |
1474 | bool transferLocations(const List<Clause> &from, List<Clause> &to) { |
1475 | bool allDone = true; |
1476 | |
1477 | for (Clause &clause : to) { |
1478 | if (!clause.source.empty()) |
1479 | continue; |
1480 | auto found = |
1481 | llvm::find_if(Range: from, P: [&](const Clause &c) { return c.id == clause.id; }); |
1482 | // This is not completely accurate, but should be good enough for now. |
1483 | // It can be improved in the future if necessary, but in cases of |
1484 | // synthesized clauses getting accurate location may be impossible. |
1485 | if (found != from.end()) { |
1486 | clause.source = found->source; |
1487 | } else { |
1488 | // Found a clause that won't have "source". |
1489 | allDone = false; |
1490 | } |
1491 | } |
1492 | |
1493 | return allDone; |
1494 | } |
1495 | |
1496 | } // namespace Fortran::lower::omp |
1497 | |