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

source code of flang/lib/Lower/OpenMP/Clauses.cpp