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

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