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/Parser/parse-tree.h" |
14 | #include "flang/Semantics/expression.h" |
15 | #include "flang/Semantics/symbol.h" |
16 | |
17 | #include "llvm/Frontend/OpenMP/OMPConstants.h" |
18 | |
19 | #include <list> |
20 | #include <optional> |
21 | #include <tuple> |
22 | #include <utility> |
23 | #include <variant> |
24 | |
25 | namespace detail { |
26 | template <typename C> |
27 | llvm::omp::Clause getClauseIdForClass(C &&) { |
28 | using namespace Fortran; |
29 | using A = llvm::remove_cvref_t<C>; // A is referenced in OMP.inc |
30 | // The code included below contains a sequence of checks like the following |
31 | // for each OpenMP clause |
32 | // if constexpr (std::is_same_v<A, parser::OmpClause::AcqRel>) |
33 | // return llvm::omp::Clause::OMPC_acq_rel; |
34 | // [...] |
35 | #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP |
36 | #include "llvm/Frontend/OpenMP/OMP.inc" |
37 | } |
38 | } // namespace detail |
39 | |
40 | static llvm::omp::Clause getClauseId(const Fortran::parser::OmpClause &clause) { |
41 | return std::visit([](auto &&s) { return detail::getClauseIdForClass(s); }, |
42 | clause.u); |
43 | } |
44 | |
45 | namespace Fortran::lower::omp { |
46 | using SymbolWithDesignator = std::tuple<semantics::Symbol *, MaybeExpr>; |
47 | |
48 | struct SymbolAndDesignatorExtractor { |
49 | template <typename T> |
50 | static T &&AsRvalueRef(T &&t) { |
51 | return std::move(t); |
52 | } |
53 | template <typename T> |
54 | static T AsRvalueRef(const T &t) { |
55 | return t; |
56 | } |
57 | |
58 | static semantics::Symbol *symbol_addr(const evaluate::SymbolRef &ref) { |
59 | // Symbols cannot be created after semantic checks, so all symbol |
60 | // pointers that are non-null must point to one of those pre-existing |
61 | // objects. Throughout the code, symbols are often pointed to by |
62 | // non-const pointers, so there is no harm in casting the constness |
63 | // away. |
64 | return const_cast<semantics::Symbol *>(&ref.get()); |
65 | } |
66 | |
67 | template <typename T> |
68 | static SymbolWithDesignator visit(T &&) { |
69 | // Use this to see missing overloads: |
70 | // llvm::errs() << "NULL: " << __PRETTY_FUNCTION__ << '\n'; |
71 | return SymbolWithDesignator{}; |
72 | } |
73 | |
74 | template <typename T> |
75 | static SymbolWithDesignator visit(const evaluate::Designator<T> &e) { |
76 | return std::make_tuple(symbol_addr(*e.GetLastSymbol()), |
77 | evaluate::AsGenericExpr(AsRvalueRef(e))); |
78 | } |
79 | |
80 | static SymbolWithDesignator visit(const evaluate::ProcedureDesignator &e) { |
81 | return std::make_tuple(symbol_addr(*e.GetSymbol()), std::nullopt); |
82 | } |
83 | |
84 | template <typename T> |
85 | static SymbolWithDesignator visit(const evaluate::Expr<T> &e) { |
86 | return std::visit([](auto &&s) { return visit(s); }, e.u); |
87 | } |
88 | |
89 | static void verify(const SymbolWithDesignator &sd) { |
90 | const semantics::Symbol *symbol = std::get<0>(sd); |
91 | assert(symbol && "Expecting symbol" ); |
92 | auto &maybeDsg = std::get<1>(sd); |
93 | if (!maybeDsg) |
94 | return; // Symbol with no designator -> OK |
95 | std::optional<evaluate::DataRef> maybeRef = |
96 | evaluate::ExtractDataRef(*maybeDsg); |
97 | if (maybeRef) { |
98 | if (&maybeRef->GetLastSymbol() == symbol) |
99 | return; // Symbol with a designator for it -> OK |
100 | llvm_unreachable("Expecting designator for given symbol" ); |
101 | } else { |
102 | // This could still be a Substring or ComplexPart, but at least Substring |
103 | // is not allowed in OpenMP. |
104 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
105 | maybeDsg->dump(); |
106 | #endif |
107 | llvm_unreachable("Expecting DataRef designator" ); |
108 | } |
109 | } |
110 | }; |
111 | |
112 | SymbolWithDesignator getSymbolAndDesignator(const MaybeExpr &expr) { |
113 | if (!expr) |
114 | return SymbolWithDesignator{}; |
115 | return std::visit( |
116 | [](auto &&s) { return SymbolAndDesignatorExtractor::visit(s); }, expr->u); |
117 | } |
118 | |
119 | Object makeObject(const parser::Name &name, |
120 | semantics::SemanticsContext &semaCtx) { |
121 | assert(name.symbol && "Expecting Symbol" ); |
122 | return Object{name.symbol, std::nullopt}; |
123 | } |
124 | |
125 | Object makeObject(const parser::Designator &dsg, |
126 | semantics::SemanticsContext &semaCtx) { |
127 | evaluate::ExpressionAnalyzer ea{semaCtx}; |
128 | SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(dsg)); |
129 | SymbolAndDesignatorExtractor::verify(sd); |
130 | return Object{std::get<0>(sd), std::move(std::get<1>(sd))}; |
131 | } |
132 | |
133 | Object makeObject(const parser::StructureComponent &comp, |
134 | semantics::SemanticsContext &semaCtx) { |
135 | evaluate::ExpressionAnalyzer ea{semaCtx}; |
136 | SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(comp)); |
137 | SymbolAndDesignatorExtractor::verify(sd); |
138 | return Object{std::get<0>(sd), std::move(std::get<1>(sd))}; |
139 | } |
140 | |
141 | Object makeObject(const parser::OmpObject &object, |
142 | semantics::SemanticsContext &semaCtx) { |
143 | // If object is a common block, expression analyzer won't be able to |
144 | // do anything. |
145 | if (const auto *name = std::get_if<parser::Name>(&object.u)) { |
146 | assert(name->symbol && "Expecting Symbol" ); |
147 | return Object{name->symbol, std::nullopt}; |
148 | } |
149 | // OmpObject is std::variant<Designator, /*common block*/ Name>; |
150 | return makeObject(std::get<parser::Designator>(object.u), semaCtx); |
151 | } |
152 | |
153 | std::optional<Object> |
154 | getBaseObject(const Object &object, |
155 | Fortran::semantics::SemanticsContext &semaCtx) { |
156 | // If it's just the symbol, then there is no base. |
157 | if (!object.id()) |
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 (base.UnwrapSymbolRef()) { |
182 | return std::nullopt; |
183 | } |
184 | } else { |
185 | assert(std::holds_alternative<evaluate::CoarrayRef>(ref.u) && |
186 | "Unexpected variant alternative" ); |
187 | llvm_unreachable("Coarray reference not supported at the moment" ); |
188 | } |
189 | return std::nullopt; |
190 | } |
191 | |
192 | // Helper macros |
193 | #define MAKE_EMPTY_CLASS(cls, from_cls) \ |
194 | cls make(const parser::OmpClause::from_cls &, \ |
195 | semantics::SemanticsContext &) { \ |
196 | static_assert(cls::EmptyTrait::value); \ |
197 | return cls{}; \ |
198 | } \ |
199 | [[maybe_unused]] extern int xyzzy_semicolon_absorber |
200 | |
201 | #define MAKE_INCOMPLETE_CLASS(cls, from_cls) \ |
202 | cls make(const parser::OmpClause::from_cls &, \ |
203 | semantics::SemanticsContext &) { \ |
204 | static_assert(cls::IncompleteTrait::value); \ |
205 | return cls{}; \ |
206 | } \ |
207 | [[maybe_unused]] extern int xyzzy_semicolon_absorber |
208 | |
209 | #define MS(x, y) CLAUSET_SCOPED_ENUM_MEMBER_CONVERT(x, y) |
210 | #define MU(x, y) CLAUSET_UNSCOPED_ENUM_MEMBER_CONVERT(x, y) |
211 | |
212 | namespace clause { |
213 | MAKE_EMPTY_CLASS(AcqRel, AcqRel); |
214 | MAKE_EMPTY_CLASS(Acquire, Acquire); |
215 | MAKE_EMPTY_CLASS(Capture, Capture); |
216 | MAKE_EMPTY_CLASS(Compare, Compare); |
217 | MAKE_EMPTY_CLASS(DynamicAllocators, DynamicAllocators); |
218 | MAKE_EMPTY_CLASS(Full, Full); |
219 | MAKE_EMPTY_CLASS(Inbranch, Inbranch); |
220 | MAKE_EMPTY_CLASS(Mergeable, Mergeable); |
221 | MAKE_EMPTY_CLASS(Nogroup, Nogroup); |
222 | // MAKE_EMPTY_CLASS(NoOpenmp, ); // missing-in-parser |
223 | // MAKE_EMPTY_CLASS(NoOpenmpRoutines, ); // missing-in-parser |
224 | // MAKE_EMPTY_CLASS(NoParallelism, ); // missing-in-parser |
225 | MAKE_EMPTY_CLASS(Notinbranch, Notinbranch); |
226 | MAKE_EMPTY_CLASS(Nowait, Nowait); |
227 | MAKE_EMPTY_CLASS(OmpxAttribute, OmpxAttribute); |
228 | MAKE_EMPTY_CLASS(OmpxBare, OmpxBare); |
229 | MAKE_EMPTY_CLASS(Read, Read); |
230 | MAKE_EMPTY_CLASS(Relaxed, Relaxed); |
231 | MAKE_EMPTY_CLASS(Release, Release); |
232 | MAKE_EMPTY_CLASS(ReverseOffload, ReverseOffload); |
233 | MAKE_EMPTY_CLASS(SeqCst, SeqCst); |
234 | MAKE_EMPTY_CLASS(Simd, Simd); |
235 | MAKE_EMPTY_CLASS(Threads, Threads); |
236 | MAKE_EMPTY_CLASS(UnifiedAddress, UnifiedAddress); |
237 | MAKE_EMPTY_CLASS(UnifiedSharedMemory, UnifiedSharedMemory); |
238 | MAKE_EMPTY_CLASS(Unknown, Unknown); |
239 | MAKE_EMPTY_CLASS(Untied, Untied); |
240 | MAKE_EMPTY_CLASS(Weak, Weak); |
241 | MAKE_EMPTY_CLASS(Write, Write); |
242 | |
243 | // Artificial clauses |
244 | MAKE_EMPTY_CLASS(CancellationConstructType, CancellationConstructType); |
245 | MAKE_EMPTY_CLASS(Depobj, Depobj); |
246 | MAKE_EMPTY_CLASS(Flush, Flush); |
247 | MAKE_EMPTY_CLASS(MemoryOrder, MemoryOrder); |
248 | MAKE_EMPTY_CLASS(Threadprivate, Threadprivate); |
249 | |
250 | MAKE_INCOMPLETE_CLASS(AdjustArgs, AdjustArgs); |
251 | MAKE_INCOMPLETE_CLASS(AppendArgs, AppendArgs); |
252 | MAKE_INCOMPLETE_CLASS(Match, Match); |
253 | // MAKE_INCOMPLETE_CLASS(Otherwise, ); // missing-in-parser |
254 | MAKE_INCOMPLETE_CLASS(When, When); |
255 | |
256 | DefinedOperator makeDefinedOperator(const parser::DefinedOperator &inp, |
257 | semantics::SemanticsContext &semaCtx) { |
258 | CLAUSET_ENUM_CONVERT( // |
259 | convert, parser::DefinedOperator::IntrinsicOperator, |
260 | DefinedOperator::IntrinsicOperator, |
261 | // clang-format off |
262 | MS(Add, Add) |
263 | MS(AND, AND) |
264 | MS(Concat, Concat) |
265 | MS(Divide, Divide) |
266 | MS(EQ, EQ) |
267 | MS(EQV, EQV) |
268 | MS(GE, GE) |
269 | MS(GT, GT) |
270 | MS(NOT, NOT) |
271 | MS(LE, LE) |
272 | MS(LT, LT) |
273 | MS(Multiply, Multiply) |
274 | MS(NE, NE) |
275 | MS(NEQV, NEQV) |
276 | MS(OR, OR) |
277 | MS(Power, Power) |
278 | MS(Subtract, Subtract) |
279 | // clang-format on |
280 | ); |
281 | |
282 | return std::visit( |
283 | common::visitors{ |
284 | [&](const parser::DefinedOpName &s) { |
285 | return DefinedOperator{ |
286 | DefinedOperator::DefinedOpName{makeObject(s.v, semaCtx)}}; |
287 | }, |
288 | [&](const parser::DefinedOperator::IntrinsicOperator &s) { |
289 | return DefinedOperator{convert(s)}; |
290 | }, |
291 | }, |
292 | inp.u); |
293 | } |
294 | |
295 | ProcedureDesignator |
296 | makeProcedureDesignator(const parser::ProcedureDesignator &inp, |
297 | semantics::SemanticsContext &semaCtx) { |
298 | return ProcedureDesignator{std::visit( |
299 | common::visitors{ |
300 | [&](const parser::Name &t) { return makeObject(t, semaCtx); }, |
301 | [&](const parser::ProcComponentRef &t) { |
302 | return makeObject(t.v.thing, semaCtx); |
303 | }, |
304 | }, |
305 | inp.u)}; |
306 | } |
307 | |
308 | ReductionOperator makeReductionOperator(const parser::OmpReductionOperator &inp, |
309 | semantics::SemanticsContext &semaCtx) { |
310 | return std::visit( |
311 | common::visitors{ |
312 | [&](const parser::DefinedOperator &s) { |
313 | return ReductionOperator{makeDefinedOperator(s, semaCtx)}; |
314 | }, |
315 | [&](const parser::ProcedureDesignator &s) { |
316 | return ReductionOperator{makeProcedureDesignator(s, semaCtx)}; |
317 | }, |
318 | }, |
319 | inp.u); |
320 | } |
321 | |
322 | // -------------------------------------------------------------------- |
323 | // Actual clauses. Each T (where tomp::T exists in ClauseT) has its "make". |
324 | |
325 | // Absent: missing-in-parser |
326 | // AcqRel: empty |
327 | // Acquire: empty |
328 | // AdjustArgs: incomplete |
329 | |
330 | Affinity make(const parser::OmpClause::Affinity &inp, |
331 | semantics::SemanticsContext &semaCtx) { |
332 | // inp -> empty |
333 | llvm_unreachable("Empty: affinity" ); |
334 | } |
335 | |
336 | Align make(const parser::OmpClause::Align &inp, |
337 | semantics::SemanticsContext &semaCtx) { |
338 | // inp -> empty |
339 | llvm_unreachable("Empty: align" ); |
340 | } |
341 | |
342 | Aligned make(const parser::OmpClause::Aligned &inp, |
343 | semantics::SemanticsContext &semaCtx) { |
344 | // inp.v -> parser::OmpAlignedClause |
345 | auto &t0 = std::get<parser::OmpObjectList>(inp.v.t); |
346 | auto &t1 = std::get<std::optional<parser::ScalarIntConstantExpr>>(inp.v.t); |
347 | |
348 | return Aligned{{ |
349 | /*Alignment=*/maybeApply(makeExprFn(semaCtx), t1), |
350 | /*List=*/makeObjects(t0, semaCtx), |
351 | }}; |
352 | } |
353 | |
354 | Allocate make(const parser::OmpClause::Allocate &inp, |
355 | semantics::SemanticsContext &semaCtx) { |
356 | // inp.v -> parser::OmpAllocateClause |
357 | using wrapped = parser::OmpAllocateClause; |
358 | auto &t0 = std::get<std::optional<wrapped::AllocateModifier>>(inp.v.t); |
359 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
360 | |
361 | if (!t0) { |
362 | return Allocate{{/*AllocatorSimpleModifier=*/std::nullopt, |
363 | /*AllocatorComplexModifier=*/std::nullopt, |
364 | /*AlignModifier=*/std::nullopt, |
365 | /*List=*/makeObjects(t1, semaCtx)}}; |
366 | } |
367 | |
368 | using Tuple = decltype(Allocate::t); |
369 | |
370 | return Allocate{std::visit( |
371 | common::visitors{ |
372 | // simple-modifier |
373 | [&](const wrapped::AllocateModifier::Allocator &v) -> Tuple { |
374 | return {/*AllocatorSimpleModifier=*/makeExpr(v.v, semaCtx), |
375 | /*AllocatorComplexModifier=*/std::nullopt, |
376 | /*AlignModifier=*/std::nullopt, |
377 | /*List=*/makeObjects(t1, semaCtx)}; |
378 | }, |
379 | // complex-modifier + align-modifier |
380 | [&](const wrapped::AllocateModifier::ComplexModifier &v) -> Tuple { |
381 | auto &s0 = std::get<wrapped::AllocateModifier::Allocator>(v.t); |
382 | auto &s1 = std::get<wrapped::AllocateModifier::Align>(v.t); |
383 | return { |
384 | /*AllocatorSimpleModifier=*/std::nullopt, |
385 | /*AllocatorComplexModifier=*/Allocator{makeExpr(s0.v, semaCtx)}, |
386 | /*AlignModifier=*/Align{makeExpr(s1.v, semaCtx)}, |
387 | /*List=*/makeObjects(t1, semaCtx)}; |
388 | }, |
389 | // align-modifier |
390 | [&](const wrapped::AllocateModifier::Align &v) -> Tuple { |
391 | return {/*AllocatorSimpleModifier=*/std::nullopt, |
392 | /*AllocatorComplexModifier=*/std::nullopt, |
393 | /*AlignModifier=*/Align{makeExpr(v.v, semaCtx)}, |
394 | /*List=*/makeObjects(t1, semaCtx)}; |
395 | }, |
396 | }, |
397 | t0->u)}; |
398 | } |
399 | |
400 | Allocator make(const parser::OmpClause::Allocator &inp, |
401 | semantics::SemanticsContext &semaCtx) { |
402 | // inp.v -> parser::ScalarIntExpr |
403 | return Allocator{/*Allocator=*/makeExpr(inp.v, semaCtx)}; |
404 | } |
405 | |
406 | // AppendArgs: incomplete |
407 | |
408 | At make(const parser::OmpClause::At &inp, |
409 | semantics::SemanticsContext &semaCtx) { |
410 | // inp -> empty |
411 | llvm_unreachable("Empty: at" ); |
412 | } |
413 | |
414 | // Never called, but needed for using "make" as a Clause visitor. |
415 | // See comment about "requires" clauses in Clauses.h. |
416 | AtomicDefaultMemOrder make(const parser::OmpClause::AtomicDefaultMemOrder &inp, |
417 | semantics::SemanticsContext &semaCtx) { |
418 | // inp.v -> parser::OmpAtomicDefaultMemOrderClause |
419 | CLAUSET_ENUM_CONVERT( // |
420 | convert, common::OmpAtomicDefaultMemOrderType, |
421 | AtomicDefaultMemOrder::MemoryOrder, |
422 | // clang-format off |
423 | MS(AcqRel, AcqRel) |
424 | MS(Relaxed, Relaxed) |
425 | MS(SeqCst, SeqCst) |
426 | // clang-format on |
427 | ); |
428 | |
429 | return AtomicDefaultMemOrder{/*MemoryOrder=*/convert(inp.v.v)}; |
430 | } |
431 | |
432 | Bind make(const parser::OmpClause::Bind &inp, |
433 | semantics::SemanticsContext &semaCtx) { |
434 | // inp -> empty |
435 | llvm_unreachable("Empty: bind" ); |
436 | } |
437 | |
438 | // CancellationConstructType: empty |
439 | // Capture: empty |
440 | |
441 | Collapse make(const parser::OmpClause::Collapse &inp, |
442 | semantics::SemanticsContext &semaCtx) { |
443 | // inp.v -> parser::ScalarIntConstantExpr |
444 | return Collapse{/*N=*/makeExpr(inp.v, semaCtx)}; |
445 | } |
446 | |
447 | // Compare: empty |
448 | // Contains: missing-in-parser |
449 | |
450 | Copyin make(const parser::OmpClause::Copyin &inp, |
451 | semantics::SemanticsContext &semaCtx) { |
452 | // inp.v -> parser::OmpObjectList |
453 | return Copyin{/*List=*/makeObjects(inp.v, semaCtx)}; |
454 | } |
455 | |
456 | Copyprivate make(const parser::OmpClause::Copyprivate &inp, |
457 | semantics::SemanticsContext &semaCtx) { |
458 | // inp.v -> parser::OmpObjectList |
459 | return Copyprivate{/*List=*/makeObjects(inp.v, semaCtx)}; |
460 | } |
461 | |
462 | Default make(const parser::OmpClause::Default &inp, |
463 | semantics::SemanticsContext &semaCtx) { |
464 | // inp.v -> parser::OmpDefaultClause |
465 | using wrapped = parser::OmpDefaultClause; |
466 | |
467 | CLAUSET_ENUM_CONVERT( // |
468 | convert, wrapped::Type, Default::DataSharingAttribute, |
469 | // clang-format off |
470 | MS(Firstprivate, Firstprivate) |
471 | MS(None, None) |
472 | MS(Private, Private) |
473 | MS(Shared, Shared) |
474 | // clang-format on |
475 | ); |
476 | |
477 | return Default{/*DataSharingAttribute=*/convert(inp.v.v)}; |
478 | } |
479 | |
480 | Defaultmap make(const parser::OmpClause::Defaultmap &inp, |
481 | semantics::SemanticsContext &semaCtx) { |
482 | // inp.v -> parser::OmpDefaultmapClause |
483 | using wrapped = parser::OmpDefaultmapClause; |
484 | |
485 | CLAUSET_ENUM_CONVERT( // |
486 | convert1, wrapped::ImplicitBehavior, Defaultmap::ImplicitBehavior, |
487 | // clang-format off |
488 | MS(Alloc, Alloc) |
489 | MS(To, To) |
490 | MS(From, From) |
491 | MS(Tofrom, Tofrom) |
492 | MS(Firstprivate, Firstprivate) |
493 | MS(None, None) |
494 | MS(Default, Default) |
495 | // MS(, Present) missing-in-parser |
496 | // clang-format on |
497 | ); |
498 | |
499 | CLAUSET_ENUM_CONVERT( // |
500 | convert2, wrapped::VariableCategory, Defaultmap::VariableCategory, |
501 | // clang-format off |
502 | MS(Scalar, Scalar) |
503 | MS(Aggregate, Aggregate) |
504 | MS(Pointer, Pointer) |
505 | MS(Allocatable, Allocatable) |
506 | // clang-format on |
507 | ); |
508 | |
509 | auto &t0 = std::get<wrapped::ImplicitBehavior>(inp.v.t); |
510 | auto &t1 = std::get<std::optional<wrapped::VariableCategory>>(inp.v.t); |
511 | return Defaultmap{{/*ImplicitBehavior=*/convert1(t0), |
512 | /*VariableCategory=*/maybeApply(convert2, t1)}}; |
513 | } |
514 | |
515 | Depend make(const parser::OmpClause::Depend &inp, |
516 | semantics::SemanticsContext &semaCtx) { |
517 | // inp.v -> parser::OmpDependClause |
518 | using wrapped = parser::OmpDependClause; |
519 | using Variant = decltype(Depend::u); |
520 | // Iteration is the equivalent of parser::OmpDependSinkVec |
521 | using Iteration = Doacross::Vector::value_type; // LoopIterationT |
522 | |
523 | CLAUSET_ENUM_CONVERT( // |
524 | convert1, parser::OmpDependenceType::Type, Depend::TaskDependenceType, |
525 | // clang-format off |
526 | MS(In, In) |
527 | MS(Out, Out) |
528 | MS(Inout, Inout) |
529 | // MS(, Mutexinoutset) // missing-in-parser |
530 | // MS(, Inputset) // missing-in-parser |
531 | // MS(, Depobj) // missing-in-parser |
532 | // clang-format on |
533 | ); |
534 | |
535 | return Depend{std::visit( // |
536 | common::visitors{ |
537 | // Doacross |
538 | [&](const wrapped::Source &s) -> Variant { |
539 | return Doacross{ |
540 | {/*DependenceType=*/Doacross::DependenceType::Source, |
541 | /*Vector=*/{}}}; |
542 | }, |
543 | // Doacross |
544 | [&](const wrapped::Sink &s) -> Variant { |
545 | using DependLength = parser::OmpDependSinkVecLength; |
546 | auto convert2 = [&](const parser::OmpDependSinkVec &v) { |
547 | auto &t0 = std::get<parser::Name>(v.t); |
548 | auto &t1 = std::get<std::optional<DependLength>>(v.t); |
549 | |
550 | auto convert3 = [&](const DependLength &u) { |
551 | auto &s0 = std::get<parser::DefinedOperator>(u.t); |
552 | auto &s1 = std::get<parser::ScalarIntConstantExpr>(u.t); |
553 | return Iteration::Distance{ |
554 | {makeDefinedOperator(s0, semaCtx), makeExpr(s1, semaCtx)}}; |
555 | }; |
556 | return Iteration{ |
557 | {makeObject(t0, semaCtx), maybeApply(convert3, t1)}}; |
558 | }; |
559 | return Doacross{{/*DependenceType=*/Doacross::DependenceType::Sink, |
560 | /*Vector=*/makeList(s.v, convert2)}}; |
561 | }, |
562 | // Depend::WithLocators |
563 | [&](const wrapped::InOut &s) -> Variant { |
564 | auto &t0 = std::get<parser::OmpDependenceType>(s.t); |
565 | auto &t1 = std::get<std::list<parser::Designator>>(s.t); |
566 | auto convert4 = [&](const parser::Designator &t) { |
567 | return makeObject(t, semaCtx); |
568 | }; |
569 | return Depend::WithLocators{ |
570 | {/*TaskDependenceType=*/convert1(t0.v), |
571 | /*Iterator=*/std::nullopt, |
572 | /*LocatorList=*/makeList(t1, convert4)}}; |
573 | }, |
574 | }, |
575 | inp.v.u)}; |
576 | } |
577 | |
578 | // Depobj: empty |
579 | |
580 | Destroy make(const parser::OmpClause::Destroy &inp, |
581 | semantics::SemanticsContext &semaCtx) { |
582 | // inp -> empty |
583 | llvm_unreachable("Empty: destroy" ); |
584 | } |
585 | |
586 | Detach make(const parser::OmpClause::Detach &inp, |
587 | semantics::SemanticsContext &semaCtx) { |
588 | // inp -> empty |
589 | llvm_unreachable("Empty: detach" ); |
590 | } |
591 | |
592 | Device make(const parser::OmpClause::Device &inp, |
593 | semantics::SemanticsContext &semaCtx) { |
594 | // inp.v -> parser::OmpDeviceClause |
595 | using wrapped = parser::OmpDeviceClause; |
596 | |
597 | CLAUSET_ENUM_CONVERT( // |
598 | convert, parser::OmpDeviceClause::DeviceModifier, Device::DeviceModifier, |
599 | // clang-format off |
600 | MS(Ancestor, Ancestor) |
601 | MS(Device_Num, DeviceNum) |
602 | // clang-format on |
603 | ); |
604 | auto &t0 = std::get<std::optional<wrapped::DeviceModifier>>(inp.v.t); |
605 | auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t); |
606 | return Device{{/*DeviceModifier=*/maybeApply(convert, t0), |
607 | /*DeviceDescription=*/makeExpr(t1, semaCtx)}}; |
608 | } |
609 | |
610 | DeviceType make(const parser::OmpClause::DeviceType &inp, |
611 | semantics::SemanticsContext &semaCtx) { |
612 | // inp.v -> parser::OmpDeviceTypeClause |
613 | using wrapped = parser::OmpDeviceTypeClause; |
614 | |
615 | CLAUSET_ENUM_CONVERT( // |
616 | convert, wrapped::Type, DeviceType::DeviceTypeDescription, |
617 | // clang-format off |
618 | MS(Any, Any) |
619 | MS(Host, Host) |
620 | MS(Nohost, Nohost) |
621 | // clang-format om |
622 | ); |
623 | return DeviceType{/*DeviceTypeDescription=*/convert(inp.v.v)}; |
624 | } |
625 | |
626 | DistSchedule make(const parser::OmpClause::DistSchedule &inp, |
627 | semantics::SemanticsContext &semaCtx) { |
628 | // inp.v -> std::optional<parser::ScalarIntExpr> |
629 | return DistSchedule{{/*Kind=*/DistSchedule::Kind::Static, |
630 | /*ChunkSize=*/maybeApply(makeExprFn(semaCtx), inp.v)}}; |
631 | } |
632 | |
633 | Doacross make(const parser::OmpClause::Doacross &inp, |
634 | semantics::SemanticsContext &semaCtx) { |
635 | // inp -> empty |
636 | llvm_unreachable("Empty: doacross" ); |
637 | } |
638 | |
639 | // DynamicAllocators: empty |
640 | |
641 | Enter make(const parser::OmpClause::Enter &inp, |
642 | semantics::SemanticsContext &semaCtx) { |
643 | // inp.v -> parser::OmpObjectList |
644 | return Enter{makeObjects(/*List=*/inp.v, semaCtx)}; |
645 | } |
646 | |
647 | Exclusive make(const parser::OmpClause::Exclusive &inp, |
648 | semantics::SemanticsContext &semaCtx) { |
649 | // inp -> empty |
650 | llvm_unreachable("Empty: exclusive" ); |
651 | } |
652 | |
653 | Fail make(const parser::OmpClause::Fail &inp, |
654 | semantics::SemanticsContext &semaCtx) { |
655 | // inp -> empty |
656 | llvm_unreachable("Empty: fail" ); |
657 | } |
658 | |
659 | Filter make(const parser::OmpClause::Filter &inp, |
660 | semantics::SemanticsContext &semaCtx) { |
661 | // inp.v -> parser::ScalarIntExpr |
662 | return Filter{/*ThreadNum=*/makeExpr(inp.v, semaCtx)}; |
663 | } |
664 | |
665 | Final make(const parser::OmpClause::Final &inp, |
666 | semantics::SemanticsContext &semaCtx) { |
667 | // inp.v -> parser::ScalarLogicalExpr |
668 | return Final{/*Finalize=*/makeExpr(inp.v, semaCtx)}; |
669 | } |
670 | |
671 | Firstprivate make(const parser::OmpClause::Firstprivate &inp, |
672 | semantics::SemanticsContext &semaCtx) { |
673 | // inp.v -> parser::OmpObjectList |
674 | return Firstprivate{/*List=*/makeObjects(inp.v, semaCtx)}; |
675 | } |
676 | |
677 | // Flush: empty |
678 | |
679 | From make(const parser::OmpClause::From &inp, |
680 | semantics::SemanticsContext &semaCtx) { |
681 | // inp.v -> parser::OmpObjectList |
682 | return From{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt, |
683 | /*Iterator=*/std::nullopt, |
684 | /*LocatorList=*/makeObjects(inp.v, semaCtx)}}; |
685 | } |
686 | |
687 | // Full: empty |
688 | |
689 | Grainsize make(const parser::OmpClause::Grainsize &inp, |
690 | semantics::SemanticsContext &semaCtx) { |
691 | // inp.v -> parser::ScalarIntExpr |
692 | return Grainsize{{/*Prescriptiveness=*/std::nullopt, |
693 | /*GrainSize=*/makeExpr(inp.v, semaCtx)}}; |
694 | } |
695 | |
696 | HasDeviceAddr make(const parser::OmpClause::HasDeviceAddr &inp, |
697 | semantics::SemanticsContext &semaCtx) { |
698 | // inp.v -> parser::OmpObjectList |
699 | return HasDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)}; |
700 | } |
701 | |
702 | Hint make(const parser::OmpClause::Hint &inp, |
703 | semantics::SemanticsContext &semaCtx) { |
704 | // inp.v -> parser::ConstantExpr |
705 | return Hint{/*HintExpr=*/makeExpr(inp.v, semaCtx)}; |
706 | } |
707 | |
708 | // Holds: missing-in-parser |
709 | |
710 | If make(const parser::OmpClause::If &inp, |
711 | semantics::SemanticsContext &semaCtx) { |
712 | // inp.v -> parser::OmpIfClause |
713 | using wrapped = parser::OmpIfClause; |
714 | |
715 | CLAUSET_ENUM_CONVERT( // |
716 | convert, wrapped::DirectiveNameModifier, llvm::omp::Directive, |
717 | // clang-format off |
718 | MS(Parallel, OMPD_parallel) |
719 | MS(Simd, OMPD_simd) |
720 | MS(Target, OMPD_target) |
721 | MS(TargetData, OMPD_target_data) |
722 | MS(TargetEnterData, OMPD_target_enter_data) |
723 | MS(TargetExitData, OMPD_target_exit_data) |
724 | MS(TargetUpdate, OMPD_target_update) |
725 | MS(Task, OMPD_task) |
726 | MS(Taskloop, OMPD_taskloop) |
727 | MS(Teams, OMPD_teams) |
728 | // clang-format on |
729 | ); |
730 | auto &t0 = std::get<std::optional<wrapped::DirectiveNameModifier>>(inp.v.t); |
731 | auto &t1 = std::get<parser::ScalarLogicalExpr>(inp.v.t); |
732 | return If{{/*DirectiveNameModifier=*/maybeApply(convert, t0), |
733 | /*IfExpression=*/makeExpr(t1, semaCtx)}}; |
734 | } |
735 | |
736 | // Inbranch: empty |
737 | |
738 | Inclusive make(const parser::OmpClause::Inclusive &inp, |
739 | semantics::SemanticsContext &semaCtx) { |
740 | // inp -> empty |
741 | llvm_unreachable("Empty: inclusive" ); |
742 | } |
743 | |
744 | Indirect make(const parser::OmpClause::Indirect &inp, |
745 | semantics::SemanticsContext &semaCtx) { |
746 | // inp -> empty |
747 | llvm_unreachable("Empty: indirect" ); |
748 | } |
749 | |
750 | Init make(const parser::OmpClause::Init &inp, |
751 | semantics::SemanticsContext &semaCtx) { |
752 | // inp -> empty |
753 | llvm_unreachable("Empty: init" ); |
754 | } |
755 | |
756 | // Initializer: missing-in-parser |
757 | |
758 | InReduction make(const parser::OmpClause::InReduction &inp, |
759 | semantics::SemanticsContext &semaCtx) { |
760 | // inp.v -> parser::OmpInReductionClause |
761 | auto &t0 = std::get<parser::OmpReductionOperator>(inp.v.t); |
762 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
763 | return InReduction{ |
764 | {/*ReductionIdentifiers=*/{makeReductionOperator(t0, semaCtx)}, |
765 | /*List=*/makeObjects(t1, semaCtx)}}; |
766 | } |
767 | |
768 | IsDevicePtr make(const parser::OmpClause::IsDevicePtr &inp, |
769 | semantics::SemanticsContext &semaCtx) { |
770 | // inp.v -> parser::OmpObjectList |
771 | return IsDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)}; |
772 | } |
773 | |
774 | Lastprivate make(const parser::OmpClause::Lastprivate &inp, |
775 | semantics::SemanticsContext &semaCtx) { |
776 | // inp.v -> parser::OmpObjectList |
777 | return Lastprivate{{/*LastprivateModifier=*/std::nullopt, |
778 | /*List=*/makeObjects(inp.v, semaCtx)}}; |
779 | } |
780 | |
781 | Linear make(const parser::OmpClause::Linear &inp, |
782 | semantics::SemanticsContext &semaCtx) { |
783 | // inp.v -> parser::OmpLinearClause |
784 | using wrapped = parser::OmpLinearClause; |
785 | |
786 | CLAUSET_ENUM_CONVERT( // |
787 | convert, parser::OmpLinearModifier::Type, Linear::LinearModifier, |
788 | // clang-format off |
789 | MS(Ref, Ref) |
790 | MS(Val, Val) |
791 | MS(Uval, Uval) |
792 | // clang-format on |
793 | ); |
794 | |
795 | using Tuple = decltype(Linear::t); |
796 | |
797 | return Linear{std::visit( |
798 | common::visitors{ |
799 | [&](const wrapped::WithModifier &s) -> Tuple { |
800 | return { |
801 | /*StepSimpleModifier=*/std::nullopt, |
802 | /*StepComplexModifier=*/maybeApply(makeExprFn(semaCtx), s.step), |
803 | /*LinearModifier=*/convert(s.modifier.v), |
804 | /*List=*/makeList(s.names, makeObjectFn(semaCtx))}; |
805 | }, |
806 | [&](const wrapped::WithoutModifier &s) -> Tuple { |
807 | return { |
808 | /*StepSimpleModifier=*/maybeApply(makeExprFn(semaCtx), s.step), |
809 | /*StepComplexModifier=*/std::nullopt, |
810 | /*LinearModifier=*/std::nullopt, |
811 | /*List=*/makeList(s.names, makeObjectFn(semaCtx))}; |
812 | }, |
813 | }, |
814 | inp.v.u)}; |
815 | } |
816 | |
817 | Link make(const parser::OmpClause::Link &inp, |
818 | semantics::SemanticsContext &semaCtx) { |
819 | // inp.v -> parser::OmpObjectList |
820 | return Link{/*List=*/makeObjects(inp.v, semaCtx)}; |
821 | } |
822 | |
823 | Map make(const parser::OmpClause::Map &inp, |
824 | semantics::SemanticsContext &semaCtx) { |
825 | // inp.v -> parser::OmpMapClause |
826 | |
827 | CLAUSET_ENUM_CONVERT( // |
828 | convert1, parser::OmpMapType::Type, Map::MapType, |
829 | // clang-format off |
830 | MS(To, To) |
831 | MS(From, From) |
832 | MS(Tofrom, Tofrom) |
833 | MS(Alloc, Alloc) |
834 | MS(Release, Release) |
835 | MS(Delete, Delete) |
836 | // clang-format on |
837 | ); |
838 | |
839 | // No convert2: MapTypeModifier is not an enum in parser. |
840 | |
841 | auto &t0 = std::get<std::optional<parser::OmpMapType>>(inp.v.t); |
842 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
843 | |
844 | if (!t0) { |
845 | return Map{{/*MapType=*/std::nullopt, /*MapTypeModifiers=*/std::nullopt, |
846 | /*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt, |
847 | /*LocatorList=*/makeObjects(t1, semaCtx)}}; |
848 | } |
849 | |
850 | auto &s0 = std::get<std::optional<parser::OmpMapType::Always>>(t0->t); |
851 | auto &s1 = std::get<parser::OmpMapType::Type>(t0->t); |
852 | |
853 | std::optional<Map::MapTypeModifiers> maybeList; |
854 | if (s0) |
855 | maybeList = Map::MapTypeModifiers{Map::MapTypeModifier::Always}; |
856 | |
857 | return Map{{/*MapType=*/convert1(s1), |
858 | /*MapTypeModifiers=*/maybeList, |
859 | /*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt, |
860 | /*LocatorList=*/makeObjects(t1, semaCtx)}}; |
861 | } |
862 | |
863 | // Match: incomplete |
864 | // MemoryOrder: empty |
865 | // Mergeable: empty |
866 | |
867 | Message make(const parser::OmpClause::Message &inp, |
868 | semantics::SemanticsContext &semaCtx) { |
869 | // inp -> empty |
870 | llvm_unreachable("Empty: message" ); |
871 | } |
872 | |
873 | Nocontext make(const parser::OmpClause::Nocontext &inp, |
874 | semantics::SemanticsContext &semaCtx) { |
875 | // inp.v -> parser::ScalarLogicalExpr |
876 | return Nocontext{/*DoNotUpdateContext=*/makeExpr(inp.v, semaCtx)}; |
877 | } |
878 | |
879 | // Nogroup: empty |
880 | |
881 | Nontemporal make(const parser::OmpClause::Nontemporal &inp, |
882 | semantics::SemanticsContext &semaCtx) { |
883 | // inp.v -> std::list<parser::Name> |
884 | return Nontemporal{/*List=*/makeList(inp.v, makeObjectFn(semaCtx))}; |
885 | } |
886 | |
887 | // NoOpenmp: missing-in-parser |
888 | // NoOpenmpRoutines: missing-in-parser |
889 | // NoParallelism: missing-in-parser |
890 | // Notinbranch: empty |
891 | |
892 | Novariants make(const parser::OmpClause::Novariants &inp, |
893 | semantics::SemanticsContext &semaCtx) { |
894 | // inp.v -> parser::ScalarLogicalExpr |
895 | return Novariants{/*DoNotUseVariant=*/makeExpr(inp.v, semaCtx)}; |
896 | } |
897 | |
898 | // Nowait: empty |
899 | |
900 | NumTasks make(const parser::OmpClause::NumTasks &inp, |
901 | semantics::SemanticsContext &semaCtx) { |
902 | // inp.v -> parser::ScalarIntExpr |
903 | return NumTasks{{/*Prescriptiveness=*/std::nullopt, |
904 | /*NumTasks=*/makeExpr(inp.v, semaCtx)}}; |
905 | } |
906 | |
907 | NumTeams make(const parser::OmpClause::NumTeams &inp, |
908 | semantics::SemanticsContext &semaCtx) { |
909 | // inp.v -> parser::ScalarIntExpr |
910 | return NumTeams{{/*LowerBound=*/std::nullopt, |
911 | /*UpperBound=*/makeExpr(inp.v, semaCtx)}}; |
912 | } |
913 | |
914 | NumThreads make(const parser::OmpClause::NumThreads &inp, |
915 | semantics::SemanticsContext &semaCtx) { |
916 | // inp.v -> parser::ScalarIntExpr |
917 | return NumThreads{/*Nthreads=*/makeExpr(inp.v, semaCtx)}; |
918 | } |
919 | |
920 | // OmpxAttribute: empty |
921 | // OmpxBare: empty |
922 | |
923 | OmpxDynCgroupMem make(const parser::OmpClause::OmpxDynCgroupMem &inp, |
924 | semantics::SemanticsContext &semaCtx) { |
925 | // inp.v -> parser::ScalarIntExpr |
926 | return OmpxDynCgroupMem{makeExpr(inp.v, semaCtx)}; |
927 | } |
928 | |
929 | Order make(const parser::OmpClause::Order &inp, |
930 | semantics::SemanticsContext &semaCtx) { |
931 | // inp.v -> parser::OmpOrderClause |
932 | using wrapped = parser::OmpOrderClause; |
933 | |
934 | CLAUSET_ENUM_CONVERT( // |
935 | convert1, parser::OmpOrderModifier::Kind, Order::OrderModifier, |
936 | // clang-format off |
937 | MS(Reproducible, Reproducible) |
938 | MS(Unconstrained, Unconstrained) |
939 | // clang-format on |
940 | ); |
941 | |
942 | CLAUSET_ENUM_CONVERT( // |
943 | convert2, wrapped::Type, Order::Ordering, |
944 | // clang-format off |
945 | MS(Concurrent, Concurrent) |
946 | // clang-format on |
947 | ); |
948 | |
949 | auto &t0 = std::get<std::optional<parser::OmpOrderModifier>>(inp.v.t); |
950 | auto &t1 = std::get<wrapped::Type>(inp.v.t); |
951 | |
952 | auto convert3 = [&](const parser::OmpOrderModifier &s) { |
953 | return std::visit( |
954 | [&](parser::OmpOrderModifier::Kind k) { return convert1(k); }, s.u); |
955 | }; |
956 | return Order{ |
957 | {/*OrderModifier=*/maybeApply(convert3, t0), /*Ordering=*/convert2(t1)}}; |
958 | } |
959 | |
960 | Ordered make(const parser::OmpClause::Ordered &inp, |
961 | semantics::SemanticsContext &semaCtx) { |
962 | // inp.v -> std::optional<parser::ScalarIntConstantExpr> |
963 | return Ordered{/*N=*/maybeApply(makeExprFn(semaCtx), inp.v)}; |
964 | } |
965 | |
966 | // Otherwise: incomplete, missing-in-parser |
967 | |
968 | Partial make(const parser::OmpClause::Partial &inp, |
969 | semantics::SemanticsContext &semaCtx) { |
970 | // inp.v -> std::optional<parser::ScalarIntConstantExpr> |
971 | return Partial{/*UnrollFactor=*/maybeApply(makeExprFn(semaCtx), inp.v)}; |
972 | } |
973 | |
974 | Priority make(const parser::OmpClause::Priority &inp, |
975 | semantics::SemanticsContext &semaCtx) { |
976 | // inp.v -> parser::ScalarIntExpr |
977 | return Priority{/*PriorityValue=*/makeExpr(inp.v, semaCtx)}; |
978 | } |
979 | |
980 | Private make(const parser::OmpClause::Private &inp, |
981 | semantics::SemanticsContext &semaCtx) { |
982 | // inp.v -> parser::OmpObjectList |
983 | return Private{/*List=*/makeObjects(inp.v, semaCtx)}; |
984 | } |
985 | |
986 | ProcBind make(const parser::OmpClause::ProcBind &inp, |
987 | semantics::SemanticsContext &semaCtx) { |
988 | // inp.v -> parser::OmpProcBindClause |
989 | using wrapped = parser::OmpProcBindClause; |
990 | |
991 | CLAUSET_ENUM_CONVERT( // |
992 | convert, wrapped::Type, ProcBind::AffinityPolicy, |
993 | // clang-format off |
994 | MS(Close, Close) |
995 | MS(Master, Master) |
996 | MS(Spread, Spread) |
997 | MS(Primary, Primary) |
998 | // clang-format on |
999 | ); |
1000 | return ProcBind{/*AffinityPolicy=*/convert(inp.v.v)}; |
1001 | } |
1002 | |
1003 | // Read: empty |
1004 | |
1005 | Reduction make(const parser::OmpClause::Reduction &inp, |
1006 | semantics::SemanticsContext &semaCtx) { |
1007 | // inp.v -> parser::OmpReductionClause |
1008 | using wrapped = parser::OmpReductionClause; |
1009 | |
1010 | CLAUSET_ENUM_CONVERT( // |
1011 | convert, wrapped::ReductionModifier, Reduction::ReductionModifier, |
1012 | // clang-format off |
1013 | MS(Inscan, Inscan) |
1014 | MS(Task, Task) |
1015 | MS(Default, Default) |
1016 | // clang-format on |
1017 | ); |
1018 | |
1019 | auto &t0 = |
1020 | std::get<std::optional<parser::OmpReductionClause::ReductionModifier>>( |
1021 | inp.v.t); |
1022 | auto &t1 = std::get<parser::OmpReductionOperator>(inp.v.t); |
1023 | auto &t2 = std::get<parser::OmpObjectList>(inp.v.t); |
1024 | return Reduction{ |
1025 | {/*ReductionModifier=*/t0 |
1026 | ? std::make_optional<Reduction::ReductionModifier>(convert(*t0)) |
1027 | : std::nullopt, |
1028 | /*ReductionIdentifiers=*/{makeReductionOperator(t1, semaCtx)}, |
1029 | /*List=*/makeObjects(t2, semaCtx)}}; |
1030 | } |
1031 | |
1032 | // Relaxed: empty |
1033 | // Release: empty |
1034 | // ReverseOffload: empty |
1035 | |
1036 | Safelen make(const parser::OmpClause::Safelen &inp, |
1037 | semantics::SemanticsContext &semaCtx) { |
1038 | // inp.v -> parser::ScalarIntConstantExpr |
1039 | return Safelen{/*Length=*/makeExpr(inp.v, semaCtx)}; |
1040 | } |
1041 | |
1042 | Schedule make(const parser::OmpClause::Schedule &inp, |
1043 | semantics::SemanticsContext &semaCtx) { |
1044 | // inp.v -> parser::OmpScheduleClause |
1045 | using wrapped = parser::OmpScheduleClause; |
1046 | |
1047 | CLAUSET_ENUM_CONVERT( // |
1048 | convert1, wrapped::ScheduleType, Schedule::Kind, |
1049 | // clang-format off |
1050 | MS(Static, Static) |
1051 | MS(Dynamic, Dynamic) |
1052 | MS(Guided, Guided) |
1053 | MS(Auto, Auto) |
1054 | MS(Runtime, Runtime) |
1055 | // clang-format on |
1056 | ); |
1057 | |
1058 | CLAUSET_ENUM_CONVERT( // |
1059 | convert2, parser::OmpScheduleModifierType::ModType, |
1060 | Schedule::OrderingModifier, |
1061 | // clang-format off |
1062 | MS(Monotonic, Monotonic) |
1063 | MS(Nonmonotonic, Nonmonotonic) |
1064 | // clang-format on |
1065 | ); |
1066 | |
1067 | CLAUSET_ENUM_CONVERT( // |
1068 | convert3, parser::OmpScheduleModifierType::ModType, |
1069 | Schedule::ChunkModifier, |
1070 | // clang-format off |
1071 | MS(Simd, Simd) |
1072 | // clang-format on |
1073 | ); |
1074 | |
1075 | auto &t0 = std::get<std::optional<parser::OmpScheduleModifier>>(inp.v.t); |
1076 | auto &t1 = std::get<wrapped::ScheduleType>(inp.v.t); |
1077 | auto &t2 = std::get<std::optional<parser::ScalarIntExpr>>(inp.v.t); |
1078 | |
1079 | if (!t0) { |
1080 | return Schedule{{/*Kind=*/convert1(t1), /*OrderingModifier=*/std::nullopt, |
1081 | /*ChunkModifier=*/std::nullopt, |
1082 | /*ChunkSize=*/maybeApply(makeExprFn(semaCtx), t2)}}; |
1083 | } |
1084 | |
1085 | // The members of parser::OmpScheduleModifier correspond to OrderingModifier, |
1086 | // and ChunkModifier, but they can appear in any order. |
1087 | auto &m1 = std::get<parser::OmpScheduleModifier::Modifier1>(t0->t); |
1088 | auto &m2 = |
1089 | std::get<std::optional<parser::OmpScheduleModifier::Modifier2>>(t0->t); |
1090 | |
1091 | std::optional<Schedule::OrderingModifier> omod; |
1092 | std::optional<Schedule::ChunkModifier> cmod; |
1093 | |
1094 | if (m1.v.v == parser::OmpScheduleModifierType::ModType::Simd) { |
1095 | // m1 is chunk-modifier |
1096 | cmod = convert3(m1.v.v); |
1097 | if (m2) |
1098 | omod = convert2(m2->v.v); |
1099 | } else { |
1100 | // m1 is ordering-modifier |
1101 | omod = convert2(m1.v.v); |
1102 | if (m2) |
1103 | cmod = convert3(m2->v.v); |
1104 | } |
1105 | |
1106 | return Schedule{{/*Kind=*/convert1(t1), |
1107 | /*OrderingModifier=*/omod, |
1108 | /*ChunkModifier=*/cmod, |
1109 | /*ChunkSize=*/maybeApply(makeExprFn(semaCtx), t2)}}; |
1110 | } |
1111 | |
1112 | // SeqCst: empty |
1113 | |
1114 | Severity make(const parser::OmpClause::Severity &inp, |
1115 | semantics::SemanticsContext &semaCtx) { |
1116 | // inp -> empty |
1117 | llvm_unreachable("Empty: severity" ); |
1118 | } |
1119 | |
1120 | Shared make(const parser::OmpClause::Shared &inp, |
1121 | semantics::SemanticsContext &semaCtx) { |
1122 | // inp.v -> parser::OmpObjectList |
1123 | return Shared{/*List=*/makeObjects(inp.v, semaCtx)}; |
1124 | } |
1125 | |
1126 | // Simd: empty |
1127 | |
1128 | Simdlen make(const parser::OmpClause::Simdlen &inp, |
1129 | semantics::SemanticsContext &semaCtx) { |
1130 | // inp.v -> parser::ScalarIntConstantExpr |
1131 | return Simdlen{/*Length=*/makeExpr(inp.v, semaCtx)}; |
1132 | } |
1133 | |
1134 | Sizes make(const parser::OmpClause::Sizes &inp, |
1135 | semantics::SemanticsContext &semaCtx) { |
1136 | // inp.v -> std::list<parser::ScalarIntExpr> |
1137 | return Sizes{/*SizeList=*/makeList(inp.v, makeExprFn(semaCtx))}; |
1138 | } |
1139 | |
1140 | TaskReduction make(const parser::OmpClause::TaskReduction &inp, |
1141 | semantics::SemanticsContext &semaCtx) { |
1142 | // inp.v -> parser::OmpReductionClause |
1143 | auto &t0 = std::get<parser::OmpReductionOperator>(inp.v.t); |
1144 | auto &t1 = std::get<parser::OmpObjectList>(inp.v.t); |
1145 | return TaskReduction{ |
1146 | {/*ReductionIdentifiers=*/{makeReductionOperator(t0, semaCtx)}, |
1147 | /*List=*/makeObjects(t1, semaCtx)}}; |
1148 | } |
1149 | |
1150 | ThreadLimit make(const parser::OmpClause::ThreadLimit &inp, |
1151 | semantics::SemanticsContext &semaCtx) { |
1152 | // inp.v -> parser::ScalarIntExpr |
1153 | return ThreadLimit{/*Threadlim=*/makeExpr(inp.v, semaCtx)}; |
1154 | } |
1155 | |
1156 | // Threadprivate: empty |
1157 | // Threads: empty |
1158 | |
1159 | To make(const parser::OmpClause::To &inp, |
1160 | semantics::SemanticsContext &semaCtx) { |
1161 | // inp.v -> parser::OmpObjectList |
1162 | return To{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt, |
1163 | /*Iterator=*/std::nullopt, |
1164 | /*LocatorList=*/makeObjects(inp.v, semaCtx)}}; |
1165 | } |
1166 | |
1167 | // UnifiedAddress: empty |
1168 | // UnifiedSharedMemory: empty |
1169 | |
1170 | Uniform make(const parser::OmpClause::Uniform &inp, |
1171 | semantics::SemanticsContext &semaCtx) { |
1172 | // inp.v -> std::list<parser::Name> |
1173 | return Uniform{/*ParameterList=*/makeList(inp.v, makeObjectFn(semaCtx))}; |
1174 | } |
1175 | |
1176 | // Unknown: empty |
1177 | // Untied: empty |
1178 | |
1179 | Update make(const parser::OmpClause::Update &inp, |
1180 | semantics::SemanticsContext &semaCtx) { |
1181 | // inp -> empty |
1182 | return Update{/*TaskDependenceType=*/std::nullopt}; |
1183 | } |
1184 | |
1185 | Use make(const parser::OmpClause::Use &inp, |
1186 | semantics::SemanticsContext &semaCtx) { |
1187 | // inp -> empty |
1188 | llvm_unreachable("Empty: use" ); |
1189 | } |
1190 | |
1191 | UseDeviceAddr make(const parser::OmpClause::UseDeviceAddr &inp, |
1192 | semantics::SemanticsContext &semaCtx) { |
1193 | // inp.v -> parser::OmpObjectList |
1194 | return UseDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)}; |
1195 | } |
1196 | |
1197 | UseDevicePtr make(const parser::OmpClause::UseDevicePtr &inp, |
1198 | semantics::SemanticsContext &semaCtx) { |
1199 | // inp.v -> parser::OmpObjectList |
1200 | return UseDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)}; |
1201 | } |
1202 | |
1203 | UsesAllocators make(const parser::OmpClause::UsesAllocators &inp, |
1204 | semantics::SemanticsContext &semaCtx) { |
1205 | // inp -> empty |
1206 | llvm_unreachable("Empty: uses_allocators" ); |
1207 | } |
1208 | |
1209 | // Weak: empty |
1210 | // When: incomplete |
1211 | // Write: empty |
1212 | } // namespace clause |
1213 | |
1214 | Clause makeClause(const Fortran::parser::OmpClause &cls, |
1215 | semantics::SemanticsContext &semaCtx) { |
1216 | return std::visit( |
1217 | [&](auto &&s) { |
1218 | return makeClause(getClauseId(cls), clause::make(s, semaCtx), |
1219 | cls.source); |
1220 | }, |
1221 | cls.u); |
1222 | } |
1223 | |
1224 | List<Clause> makeClauses(const parser::OmpClauseList &clauses, |
1225 | semantics::SemanticsContext &semaCtx) { |
1226 | return makeList(clauses.v, [&](const parser::OmpClause &s) { |
1227 | return makeClause(s, semaCtx); |
1228 | }); |
1229 | } |
1230 | } // namespace Fortran::lower::omp |
1231 | |