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