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

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