brintos

brintos / llvm-project-archived public Read only

0
0
Text · 57.1 KiB · dc49a81 Raw
1691 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Lower/OpenMP/Clauses.h"10 11#include "flang/Common/idioms.h"12#include "flang/Evaluate/expression.h"13#include "flang/Parser/parse-tree.h"14#include "flang/Semantics/expression.h"15#include "flang/Semantics/openmp-modifiers.h"16#include "flang/Semantics/symbol.h"17 18#include <list>19#include <optional>20#include <tuple>21#include <utility>22#include <variant>23 24namespace Fortran::lower::omp {25using SymbolWithDesignator = std::tuple<semantics::Symbol *, MaybeExpr>;26 27struct SymbolAndDesignatorExtractor {28  template <typename T>29  static T &&AsRvalueRef(T &&t) {30    return std::move(t);31  }32  template <typename T>33  static T AsRvalueRef(const T &t) {34    return t;35  }36 37  static semantics::Symbol *symbol_addr(const evaluate::SymbolRef &ref) {38    // Symbols cannot be created after semantic checks, so all symbol39    // pointers that are non-null must point to one of those pre-existing40    // objects. Throughout the code, symbols are often pointed to by41    // non-const pointers, so there is no harm in casting the constness42    // away.43    return const_cast<semantics::Symbol *>(&ref.get());44  }45 46  template <typename T>47  static SymbolWithDesignator visit(T &&) {48    // Use this to see missing overloads:49    // llvm::errs() << "NULL: " << __PRETTY_FUNCTION__ << '\n';50    return SymbolWithDesignator{};51  }52 53  template <typename T>54  static SymbolWithDesignator visit(const evaluate::Designator<T> &e) {55    return std::make_tuple(symbol_addr(*e.GetLastSymbol()),56                           evaluate::AsGenericExpr(AsRvalueRef(e)));57  }58 59  static SymbolWithDesignator visit(const evaluate::ProcedureDesignator &e) {60    return std::make_tuple(symbol_addr(*e.GetSymbol()), std::nullopt);61  }62 63  template <typename T>64  static SymbolWithDesignator visit(const evaluate::Expr<T> &e) {65    return Fortran::common::visit([](auto &&s) { return visit(s); }, e.u);66  }67 68  static void verify(const SymbolWithDesignator &sd) {69    const semantics::Symbol *symbol = std::get<0>(sd);70    const std::optional<evaluate::Expr<evaluate::SomeType>> &maybeDsg =71        std::get<1>(sd);72    if (!maybeDsg)73      return; // Symbol with no designator -> OK74    assert(symbol && "Expecting symbol");75    std::optional<evaluate::DataRef> maybeRef = evaluate::ExtractDataRef(76        *maybeDsg, /*intoSubstring=*/true, /*intoComplexPart=*/true);77    if (maybeRef) {78      if (&maybeRef->GetLastSymbol() == symbol)79        return; // Symbol with a designator for it -> OK80      llvm_unreachable("Expecting designator for given symbol");81    } else {82#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)83      maybeDsg->dump();84#endif85      llvm_unreachable("Expecting DataRef designator");86    }87  }88};89 90SymbolWithDesignator getSymbolAndDesignator(const MaybeExpr &expr) {91  if (!expr)92    return SymbolWithDesignator{};93  return Fortran::common::visit(94      [](auto &&s) { return SymbolAndDesignatorExtractor::visit(s); }, expr->u);95}96 97Object makeObject(const parser::Name &name,98                  semantics::SemanticsContext &semaCtx) {99  assert(name.symbol && "Expecting Symbol");100  return Object{name.symbol, std::nullopt};101}102 103Object makeObject(const parser::Designator &dsg,104                  semantics::SemanticsContext &semaCtx) {105  evaluate::ExpressionAnalyzer ea{semaCtx};106  SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(dsg));107  SymbolAndDesignatorExtractor::verify(sd);108  return Object{std::get<0>(sd), std::move(std::get<1>(sd))};109}110 111Object makeObject(const parser::StructureComponent &comp,112                  semantics::SemanticsContext &semaCtx) {113  evaluate::ExpressionAnalyzer ea{semaCtx};114  SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(comp));115  SymbolAndDesignatorExtractor::verify(sd);116  return Object{std::get<0>(sd), std::move(std::get<1>(sd))};117}118 119Object makeObject(const parser::OmpObject &object,120                  semantics::SemanticsContext &semaCtx) {121  // If object is a common block, expression analyzer won't be able to122  // do anything.123  if (const auto *name = std::get_if<parser::Name>(&object.u)) {124    assert(name->symbol && "Expecting Symbol");125    return Object{name->symbol, std::nullopt};126  }127  // OmpObject is std::variant<Designator, /*common block*/ Name>;128  return makeObject(std::get<parser::Designator>(object.u), semaCtx);129}130 131ObjectList makeObjects(const parser::OmpArgumentList &objects,132                       semantics::SemanticsContext &semaCtx) {133  return makeList(objects.v, [&](const parser::OmpArgument &arg) {134    return common::visit(135        common::visitors{136            [&](const parser::OmpLocator &locator) -> Object {137              if (auto *object = std::get_if<parser::OmpObject>(&locator.u)) {138                return makeObject(*object, semaCtx);139              }140              llvm_unreachable("Expecting object");141            },142            [](auto &&s) -> Object { //143              llvm_unreachable("Expecting object");144            },145        },146        arg.u);147  });148}149 150std::optional<Object> getBaseObject(const Object &object,151                                    semantics::SemanticsContext &semaCtx) {152  // If it's just the symbol, then there is no base.153  if (!object.ref())154    return std::nullopt;155 156  auto maybeRef = evaluate::ExtractDataRef(*object.ref());157  if (!maybeRef)158    return std::nullopt;159 160  evaluate::DataRef ref = *maybeRef;161 162  if (std::get_if<evaluate::SymbolRef>(&ref.u)) {163    return std::nullopt;164  } else if (auto *comp = std::get_if<evaluate::Component>(&ref.u)) {165    const evaluate::DataRef &base = comp->base();166    return Object{167        SymbolAndDesignatorExtractor::symbol_addr(base.GetLastSymbol()),168        evaluate::AsGenericExpr(169            SymbolAndDesignatorExtractor::AsRvalueRef(base))};170  } else if (auto *arr = std::get_if<evaluate::ArrayRef>(&ref.u)) {171    const evaluate::NamedEntity &base = arr->base();172    evaluate::ExpressionAnalyzer ea{semaCtx};173    if (auto *comp = base.UnwrapComponent()) {174      return Object{SymbolAndDesignatorExtractor::symbol_addr(comp->symbol()),175                    ea.Designate(evaluate::DataRef{176                        SymbolAndDesignatorExtractor::AsRvalueRef(*comp)})};177    } else if (auto *symRef = base.UnwrapSymbolRef()) {178      // This is the base symbol of the array reference, which is the same179      // as the symbol in the input object,180      // e.g. A(i) is represented as {Symbol(A), Designator(ArrayRef(A, i))}.181      // Here we have the Symbol(A), which is what we started with.182      (void)symRef;183      assert(&**symRef == object.sym());184      return std::nullopt;185    }186  } else {187    assert(std::holds_alternative<evaluate::CoarrayRef>(ref.u) &&188           "Unexpected variant alternative");189    llvm_unreachable("Coarray reference not supported at the moment");190  }191  return std::nullopt;192}193 194// Helper macros195#define MAKE_EMPTY_CLASS(cls, from_cls)                                        \196  cls make(const parser::OmpClause::from_cls &,                                \197           semantics::SemanticsContext &) {                                    \198    static_assert(cls::EmptyTrait::value);                                     \199    return cls{};                                                              \200  }                                                                            \201  [[maybe_unused]] extern int xyzzy_semicolon_absorber202 203#define MAKE_INCOMPLETE_CLASS(cls, from_cls)                                   \204  cls make(const parser::OmpClause::from_cls &,                                \205           semantics::SemanticsContext &) {                                    \206    static_assert(cls::IncompleteTrait::value);                                \207    return cls{};                                                              \208  }                                                                            \209  [[maybe_unused]] extern int xyzzy_semicolon_absorber210 211#define MS(x, y) CLAUSET_SCOPED_ENUM_MEMBER_CONVERT(x, y)212#define MU(x, y) CLAUSET_UNSCOPED_ENUM_MEMBER_CONVERT(x, y)213 214namespace clause {215MAKE_EMPTY_CLASS(AcqRel, AcqRel);216MAKE_EMPTY_CLASS(Acquire, Acquire);217MAKE_EMPTY_CLASS(Capture, Capture);218MAKE_EMPTY_CLASS(Compare, Compare);219MAKE_EMPTY_CLASS(Full, Full);220MAKE_EMPTY_CLASS(Inbranch, Inbranch);221MAKE_EMPTY_CLASS(Mergeable, Mergeable);222MAKE_EMPTY_CLASS(Nogroup, Nogroup);223MAKE_EMPTY_CLASS(NoOpenmp, NoOpenmp);224MAKE_EMPTY_CLASS(NoOpenmpRoutines, NoOpenmpRoutines);225MAKE_EMPTY_CLASS(NoOpenmpConstructs, NoOpenmpConstructs);226MAKE_EMPTY_CLASS(NoParallelism, NoParallelism);227MAKE_EMPTY_CLASS(Notinbranch, Notinbranch);228MAKE_EMPTY_CLASS(Nowait, Nowait);229MAKE_EMPTY_CLASS(OmpxAttribute, OmpxAttribute);230MAKE_EMPTY_CLASS(OmpxBare, OmpxBare);231MAKE_EMPTY_CLASS(Read, Read);232MAKE_EMPTY_CLASS(Relaxed, Relaxed);233MAKE_EMPTY_CLASS(Release, Release);234MAKE_EMPTY_CLASS(SeqCst, SeqCst);235MAKE_EMPTY_CLASS(Simd, Simd);236MAKE_EMPTY_CLASS(Threads, Threads);237MAKE_EMPTY_CLASS(Unknown, Unknown);238MAKE_EMPTY_CLASS(Untied, Untied);239MAKE_EMPTY_CLASS(Weak, Weak);240MAKE_EMPTY_CLASS(Write, Write);241 242// Artificial clauses243MAKE_EMPTY_CLASS(Depobj, Depobj);244MAKE_EMPTY_CLASS(Flush, Flush);245MAKE_EMPTY_CLASS(MemoryOrder, MemoryOrder);246MAKE_EMPTY_CLASS(Threadprivate, Threadprivate);247MAKE_EMPTY_CLASS(Groupprivate, Groupprivate);248 249MAKE_INCOMPLETE_CLASS(AdjustArgs, AdjustArgs);250MAKE_INCOMPLETE_CLASS(AppendArgs, AppendArgs);251MAKE_INCOMPLETE_CLASS(Collector, Collector);252MAKE_INCOMPLETE_CLASS(GraphId, GraphId);253MAKE_INCOMPLETE_CLASS(GraphReset, GraphReset);254MAKE_INCOMPLETE_CLASS(Inductor, Inductor);255MAKE_INCOMPLETE_CLASS(Replayable, Replayable);256MAKE_INCOMPLETE_CLASS(Transparent, Transparent);257 258List<IteratorSpecifier>259makeIteratorSpecifiers(const parser::OmpIteratorSpecifier &inp,260                       semantics::SemanticsContext &semaCtx) {261  List<IteratorSpecifier> specifiers;262 263  auto &[begin, end, step] = std::get<parser::SubscriptTriplet>(inp.t).t;264  assert(begin && end && "Expecting begin/end values");265  evaluate::ExpressionAnalyzer ea{semaCtx};266 267  MaybeExpr rbegin{ea.Analyze(*begin)}, rend{ea.Analyze(*end)};268  MaybeExpr rstep;269  if (step)270    rstep = ea.Analyze(*step);271 272  assert(rbegin && rend && "Unable to get range bounds");273  Range range{{*rbegin, *rend, rstep}};274 275  auto &tds = std::get<parser::TypeDeclarationStmt>(inp.t);276  auto &entities = std::get<std::list<parser::EntityDecl>>(tds.t);277  for (const parser::EntityDecl &ed : entities) {278    auto &name = std::get<parser::ObjectName>(ed.t);279    assert(name.symbol && "Expecting symbol for iterator variable");280    auto *stype = name.symbol->GetType();281    assert(stype && "Expecting symbol type");282    IteratorSpecifier spec{{evaluate::DynamicType::From(*stype),283                            makeObject(name, semaCtx), range}};284    specifiers.emplace_back(std::move(spec));285  }286 287  return specifiers;288}289 290Iterator makeIterator(const parser::OmpIterator &inp,291                      semantics::SemanticsContext &semaCtx) {292  Iterator iterator;293  for (auto &&spec : inp.v)294    llvm::append_range(iterator, makeIteratorSpecifiers(spec, semaCtx));295  return iterator;296}297 298DefinedOperator makeDefinedOperator(const parser::DefinedOperator &inp,299                                    semantics::SemanticsContext &semaCtx) {300  CLAUSET_ENUM_CONVERT( //301      convert, parser::DefinedOperator::IntrinsicOperator,302      DefinedOperator::IntrinsicOperator,303      // clang-format off304      MS(Add,      Add)305      MS(AND,      AND)306      MS(Concat,   Concat)307      MS(Divide,   Divide)308      MS(EQ,       EQ)309      MS(EQV,      EQV)310      MS(GE,       GE)311      MS(GT,       GT)312      MS(NOT,      NOT)313      MS(LE,       LE)314      MS(LT,       LT)315      MS(Multiply, Multiply)316      MS(NE,       NE)317      MS(NEQV,     NEQV)318      MS(OR,       OR)319      MS(Power,    Power)320      MS(Subtract, Subtract)321      // clang-format on322  );323 324  return Fortran::common::visit(325      common::visitors{326          [&](const parser::DefinedOpName &s) {327            return DefinedOperator{328                DefinedOperator::DefinedOpName{makeObject(s.v, semaCtx)}};329          },330          [&](const parser::DefinedOperator::IntrinsicOperator &s) {331            return DefinedOperator{convert(s)};332          },333      },334      inp.u);335}336 337ProcedureDesignator338makeProcedureDesignator(const parser::ProcedureDesignator &inp,339                        semantics::SemanticsContext &semaCtx) {340  return ProcedureDesignator{Fortran::common::visit(341      common::visitors{342          [&](const parser::Name &t) { return makeObject(t, semaCtx); },343          [&](const parser::ProcComponentRef &t) {344            return makeObject(t.v.thing, semaCtx);345          },346      },347      inp.u)};348}349 350ReductionOperator351makeReductionOperator(const parser::OmpReductionIdentifier &inp,352                      semantics::SemanticsContext &semaCtx) {353  return Fortran::common::visit(354      common::visitors{355          [&](const parser::DefinedOperator &s) {356            return ReductionOperator{makeDefinedOperator(s, semaCtx)};357          },358          [&](const parser::ProcedureDesignator &s) {359            return ReductionOperator{makeProcedureDesignator(s, semaCtx)};360          },361      },362      inp.u);363}364 365clause::DependenceType makeDepType(const parser::OmpDependenceType &inp) {366  switch (inp.v) {367  case parser::OmpDependenceType::Value::Sink:368    return clause::DependenceType::Sink;369  case parser::OmpDependenceType::Value::Source:370    return clause::DependenceType::Source;371  }372  llvm_unreachable("Unexpected dependence type");373}374 375clause::DependenceType makeDepType(const parser::OmpTaskDependenceType &inp) {376  switch (inp.v) {377  case parser::OmpTaskDependenceType::Value::Depobj:378    return clause::DependenceType::Depobj;379  case parser::OmpTaskDependenceType::Value::In:380    return clause::DependenceType::In;381  case parser::OmpTaskDependenceType::Value::Inout:382    return clause::DependenceType::Inout;383  case parser::OmpTaskDependenceType::Value::Inoutset:384    return clause::DependenceType::Inoutset;385  case parser::OmpTaskDependenceType::Value::Mutexinoutset:386    return clause::DependenceType::Mutexinoutset;387  case parser::OmpTaskDependenceType::Value::Out:388    return clause::DependenceType::Out;389  }390  llvm_unreachable("Unexpected task dependence type");391}392 393clause::Prescriptiveness394makePrescriptiveness(parser::OmpPrescriptiveness::Value v) {395  switch (v) {396  case parser::OmpPrescriptiveness::Value::Strict:397    return clause::Prescriptiveness::Strict;398  }399  llvm_unreachable("Unexpected prescriptiveness");400}401 402// --------------------------------------------------------------------403// Actual clauses. Each T (where tomp::T exists in ClauseT) has its "make".404 405Absent make(const parser::OmpClause::Absent &inp,406            semantics::SemanticsContext &semaCtx) {407  llvm_unreachable("Unimplemented: absent");408}409 410// AcqRel: empty411// Acquire: empty412// AdjustArgs: incomplete413 414Affinity make(const parser::OmpClause::Affinity &inp,415              semantics::SemanticsContext &semaCtx) {416  // inp.v -> parser::OmpAffinityClause417  auto &mods = semantics::OmpGetModifiers(inp.v);418  auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);419  auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);420 421  auto &&maybeIter =422      m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{};423 424  return Affinity{{/*Iterator=*/std::move(maybeIter),425                   /*LocatorList=*/makeObjects(t1, semaCtx)}};426}427 428Align make(const parser::OmpClause::Align &inp,429           semantics::SemanticsContext &semaCtx) {430  // inp -> empty431  llvm_unreachable("Empty: align");432}433 434Aligned make(const parser::OmpClause::Aligned &inp,435             semantics::SemanticsContext &semaCtx) {436  // inp.v -> parser::OmpAlignedClause437  auto &mods = semantics::OmpGetModifiers(inp.v);438  auto &t0 = std::get<parser::OmpObjectList>(inp.v.t);439  auto *m1 = semantics::OmpGetUniqueModifier<parser::OmpAlignment>(mods);440 441  return Aligned{{442      /*Alignment=*/maybeApplyToV(makeExprFn(semaCtx), m1),443      /*List=*/makeObjects(t0, semaCtx),444  }};445}446 447Allocate make(const parser::OmpClause::Allocate &inp,448              semantics::SemanticsContext &semaCtx) {449  // inp.v -> parser::OmpAllocateClause450  auto &mods = semantics::OmpGetModifiers(inp.v);451  auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpAlignModifier>(mods);452  auto *m1 =453      semantics::OmpGetUniqueModifier<parser::OmpAllocatorComplexModifier>(454          mods);455  auto *m2 =456      semantics::OmpGetUniqueModifier<parser::OmpAllocatorSimpleModifier>(mods);457  auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);458 459  auto makeAllocator = [&](auto *mod) -> std::optional<Allocator> {460    if (mod)461      return Allocator{makeExpr(mod->v, semaCtx)};462    return std::nullopt;463  };464 465  auto makeAlign = [&](const parser::ScalarIntExpr &expr) {466    return Align{makeExpr(expr, semaCtx)};467  };468 469  auto maybeAllocator = m1 ? makeAllocator(m1) : makeAllocator(m2);470  return Allocate{{/*AllocatorComplexModifier=*/std::move(maybeAllocator),471                   /*AlignModifier=*/maybeApplyToV(makeAlign, m0),472                   /*List=*/makeObjects(t1, semaCtx)}};473}474 475Allocator make(const parser::OmpClause::Allocator &inp,476               semantics::SemanticsContext &semaCtx) {477  // inp.v -> parser::ScalarIntExpr478  return Allocator{/*Allocator=*/makeExpr(inp.v, semaCtx)};479}480 481// AppendArgs: incomplete482 483At make(const parser::OmpClause::At &inp,484        semantics::SemanticsContext &semaCtx) {485  // inp -> empty486  llvm_unreachable("Empty: at");487}488 489// Never called, but needed for using "make" as a Clause visitor.490// See comment about "requires" clauses in Clauses.h.491AtomicDefaultMemOrder make(const parser::OmpClause::AtomicDefaultMemOrder &inp,492                           semantics::SemanticsContext &semaCtx) {493  // inp.v -> parser::OmpAtomicDefaultMemOrderClause494  CLAUSET_ENUM_CONVERT( //495      convert, common::OmpMemoryOrderType, AtomicDefaultMemOrder::MemoryOrder,496      // clang-format off497      MS(Acq_Rel,  AcqRel)498      MS(Acquire,  Acquire)499      MS(Relaxed,  Relaxed)500      MS(Release,  Release)501      MS(Seq_Cst,  SeqCst)502      // clang-format on503  );504 505  return AtomicDefaultMemOrder{/*MemoryOrder=*/convert(inp.v.v)};506}507 508Bind make(const parser::OmpClause::Bind &inp,509          semantics::SemanticsContext &semaCtx) {510  // inp.v -> parser::OmpBindClause511  using wrapped = parser::OmpBindClause;512 513  CLAUSET_ENUM_CONVERT( //514      convert, wrapped::Binding, Bind::Binding,515      // clang-format off516      MS(Teams, Teams)517      MS(Parallel, Parallel)518      MS(Thread, Thread)519      // clang-format on520  );521 522  return Bind{/*Binding=*/convert(inp.v.v)};523}524 525CancellationConstructType526make(const parser::OmpClause::CancellationConstructType &inp,527     semantics::SemanticsContext &semaCtx) {528  auto name = std::get<parser::OmpDirectiveName>(inp.v.t);529  CLAUSET_ENUM_CONVERT(530      convert, llvm::omp::Directive, llvm::omp::CancellationConstructType,531      // clang-format off532      MS(OMPD_parallel, OMP_CANCELLATION_CONSTRUCT_Parallel)533      MS(OMPD_do, OMP_CANCELLATION_CONSTRUCT_Loop)534      MS(OMPD_sections, OMP_CANCELLATION_CONSTRUCT_Sections)535      MS(OMPD_taskgroup, OMP_CANCELLATION_CONSTRUCT_Taskgroup)536      // clang-format on537  );538 539  return CancellationConstructType{convert(name.v)};540}541 542// Capture: empty543 544Collapse make(const parser::OmpClause::Collapse &inp,545              semantics::SemanticsContext &semaCtx) {546  // inp.v -> parser::ScalarIntConstantExpr547  return Collapse{/*N=*/makeExpr(inp.v, semaCtx)};548}549 550// Compare: empty551 552Contains make(const parser::OmpClause::Contains &inp,553              semantics::SemanticsContext &semaCtx) {554  llvm_unreachable("Unimplemented: contains");555}556 557Copyin make(const parser::OmpClause::Copyin &inp,558            semantics::SemanticsContext &semaCtx) {559  // inp.v -> parser::OmpObjectList560  return Copyin{/*List=*/makeObjects(inp.v, semaCtx)};561}562 563Copyprivate make(const parser::OmpClause::Copyprivate &inp,564                 semantics::SemanticsContext &semaCtx) {565  // inp.v -> parser::OmpObjectList566  return Copyprivate{/*List=*/makeObjects(inp.v, semaCtx)};567}568 569// The Default clause is overloaded in OpenMP 5.0 and 5.1: it can be either570// a data-sharing clause, or a METADIRECTIVE clause. In the latter case, it571// has been superseded by the OTHERWISE clause.572// Disambiguate this in this representation: for the DSA case, create Default,573// and in the other case create Otherwise.574Default makeDefault(const parser::OmpClause::Default &inp,575                    semantics::SemanticsContext &semaCtx) {576  // inp.v -> parser::OmpDefaultClause577  using wrapped = parser::OmpDefaultClause;578 579  CLAUSET_ENUM_CONVERT( //580      convert, wrapped::DataSharingAttribute, Default::DataSharingAttribute,581      // clang-format off582      MS(Firstprivate, Firstprivate)583      MS(None,         None)584      MS(Private,      Private)585      MS(Shared,       Shared)586      // clang-format on587  );588 589  auto dsa = std::get<wrapped::DataSharingAttribute>(inp.v.u);590  return Default{/*DataSharingAttribute=*/convert(dsa)};591}592 593Otherwise makeOtherwise(const parser::OmpClause::Default &inp,594                        semantics::SemanticsContext &semaCtx) {595  return Otherwise{};596}597 598Defaultmap make(const parser::OmpClause::Defaultmap &inp,599                semantics::SemanticsContext &semaCtx) {600  // inp.v -> parser::OmpDefaultmapClause601  using wrapped = parser::OmpDefaultmapClause;602 603  CLAUSET_ENUM_CONVERT( //604      convert1, wrapped::ImplicitBehavior, Defaultmap::ImplicitBehavior,605      // clang-format off606      MS(Alloc,        Alloc)607      MS(To,           To)608      MS(From,         From)609      MS(Tofrom,       Tofrom)610      MS(Firstprivate, Firstprivate)611      MS(None,         None)612      MS(Default,      Default)613      MS(Present,      Present)614      // clang-format on615  );616 617  CLAUSET_ENUM_CONVERT( //618      convert2, parser::OmpVariableCategory::Value,619      Defaultmap::VariableCategory,620      // clang-format off621      MS(Aggregate,    Aggregate)622      MS(All,          All)623      MS(Allocatable,  Allocatable)624      MS(Pointer,      Pointer)625      MS(Scalar,       Scalar)626      // clang-format on627  );628 629  auto &mods = semantics::OmpGetModifiers(inp.v);630  auto &t0 = std::get<wrapped::ImplicitBehavior>(inp.v.t);631  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpVariableCategory>(mods);632 633  auto category = t1 ? convert2(t1->v) : Defaultmap::VariableCategory::All;634  return Defaultmap{{/*ImplicitBehavior=*/convert1(t0),635                     /*VariableCategory=*/category}};636}637 638Doacross makeDoacross(const parser::OmpDoacross &doa,639                      semantics::SemanticsContext &semaCtx) {640  // Iteration is the equivalent of parser::OmpIteration641  using Iteration = Doacross::Vector::value_type; // LoopIterationT642 643  auto visitSource = [&](const parser::OmpDoacross::Source &) {644    return Doacross{{/*DependenceType=*/Doacross::DependenceType::Source,645                     /*Vector=*/{}}};646  };647 648  auto visitSink = [&](const parser::OmpDoacross::Sink &s) {649    using IterOffset = parser::OmpIterationOffset;650    auto convert2 = [&](const parser::OmpIteration &v) {651      auto &t0 = std::get<parser::Name>(v.t);652      auto &t1 = std::get<std::optional<IterOffset>>(v.t);653 654      auto convert3 = [&](const IterOffset &u) {655        auto &s0 = std::get<parser::DefinedOperator>(u.t);656        auto &s1 = std::get<parser::ScalarIntConstantExpr>(u.t);657        return Iteration::Distance{658            {makeDefinedOperator(s0, semaCtx), makeExpr(s1, semaCtx)}};659      };660      return Iteration{{makeObject(t0, semaCtx), maybeApply(convert3, t1)}};661    };662    return Doacross{{/*DependenceType=*/Doacross::DependenceType::Sink,663                     /*Vector=*/makeList(s.v.v, convert2)}};664  };665 666  return common::visit(common::visitors{visitSink, visitSource}, doa.u);667}668 669Depend make(const parser::OmpClause::Depend &inp,670            semantics::SemanticsContext &semaCtx) {671  // inp.v -> parser::OmpDependClause672  using wrapped = parser::OmpDependClause;673  using Variant = decltype(Depend::u);674 675  auto visitTaskDep = [&](const wrapped::TaskDep &s) -> Variant {676    auto &mods = semantics::OmpGetModifiers(s);677    auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);678    auto *m1 =679        semantics::OmpGetUniqueModifier<parser::OmpTaskDependenceType>(mods);680    auto &t1 = std::get<parser::OmpObjectList>(s.t);681    assert(m1 && "expecting task dependence type");682 683    auto &&maybeIter =684        m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{};685    return Depend::TaskDep{{/*DependenceType=*/makeDepType(*m1),686                            /*Iterator=*/std::move(maybeIter),687                            /*LocatorList=*/makeObjects(t1, semaCtx)}};688  };689 690  return Depend{common::visit( //691      common::visitors{692          // Doacross693          [&](const parser::OmpDoacross &s) -> Variant {694            return makeDoacross(s, semaCtx);695          },696          // Depend::TaskDep697          visitTaskDep,698      },699      inp.v.u)};700}701 702// Depobj: empty703 704Destroy make(const parser::OmpClause::Destroy &inp,705             semantics::SemanticsContext &semaCtx) {706  // inp.v -> std::optional<OmpDestroyClause>707  auto &&maybeObject = maybeApply(708      [&](const parser::OmpDestroyClause &c) {709        return makeObject(c.v, semaCtx);710      },711      inp.v);712 713  return Destroy{/*DestroyVar=*/std::move(maybeObject)};714}715 716Detach make(const parser::OmpClause::Detach &inp,717            semantics::SemanticsContext &semaCtx) {718  // inp.v -> parser::OmpDetachClause719  return Detach{makeObject(inp.v.v, semaCtx)};720}721 722Device make(const parser::OmpClause::Device &inp,723            semantics::SemanticsContext &semaCtx) {724  // inp.v -> parser::OmpDeviceClause725  CLAUSET_ENUM_CONVERT( //726      convert, parser::OmpDeviceModifier::Value, Device::DeviceModifier,727      // clang-format off728      MS(Ancestor,   Ancestor)729      MS(Device_Num, DeviceNum)730      // clang-format on731  );732 733  auto &mods = semantics::OmpGetModifiers(inp.v);734  auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpDeviceModifier>(mods);735  auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);736  return Device{{/*DeviceModifier=*/maybeApplyToV(convert, m0),737                 /*DeviceDescription=*/makeExpr(t1, semaCtx)}};738}739 740DeviceSafesync make(const parser::OmpClause::DeviceSafesync &inp,741                    semantics::SemanticsContext &semaCtx) {742  // inp.v -> std::optional<parser::OmpDeviceSafesyncClause>743  auto &&maybeRequired = maybeApply(744      [&](const parser::OmpDeviceSafesyncClause &c) {745        return makeExpr(c.v, semaCtx);746      },747      inp.v);748 749  return DeviceSafesync{/*Required=*/std::move(maybeRequired)};750}751 752DeviceType make(const parser::OmpClause::DeviceType &inp,753                semantics::SemanticsContext &semaCtx) {754  // inp.v -> parser::OmpDeviceTypeClause755  using wrapped = parser::OmpDeviceTypeClause;756 757  CLAUSET_ENUM_CONVERT( //758      convert, wrapped::DeviceTypeDescription,759      DeviceType::DeviceTypeDescription,760      // clang-format off761      MS(Any,    Any)762      MS(Host,   Host)763      MS(Nohost, Nohost)764      // clang-format om765  );766  return DeviceType{/*DeviceTypeDescription=*/convert(inp.v.v)};767}768 769DistSchedule make(const parser::OmpClause::DistSchedule &inp,770                  semantics::SemanticsContext &semaCtx) {771  // inp.v -> std::optional<parser::ScalarIntExpr>772  return DistSchedule{{/*Kind=*/DistSchedule::Kind::Static,773                       /*ChunkSize=*/maybeApply(makeExprFn(semaCtx), inp.v)}};774}775 776Doacross make(const parser::OmpClause::Doacross &inp,777              semantics::SemanticsContext &semaCtx) {778  // inp.v -> OmpDoacrossClause779  return makeDoacross(inp.v.v, semaCtx);780}781 782DynamicAllocators make(const parser::OmpClause::DynamicAllocators &inp,783                       semantics::SemanticsContext &semaCtx) {784  // inp.v -> td::optional<arser::OmpDynamicAllocatorsClause>785  auto &&maybeRequired = maybeApply(786      [&](const parser::OmpDynamicAllocatorsClause &c) {787        return makeExpr(c.v, semaCtx);788      },789      inp.v);790 791  return DynamicAllocators{/*Required=*/std::move(maybeRequired)};792}793 794 795DynGroupprivate make(const parser::OmpClause::DynGroupprivate &inp,796                     semantics::SemanticsContext &semaCtx) {797  // imp.v -> OmpDyngroupprivateClause798  CLAUSET_ENUM_CONVERT( //799      makeAccessGroup, parser::OmpAccessGroup::Value,800      DynGroupprivate::AccessGroup,801      // clang-format off802      MS(Cgroup,  Cgroup)803      // clang-format on804  );805 806  CLAUSET_ENUM_CONVERT( //807      makeFallback, parser::OmpFallbackModifier::Value,808      DynGroupprivate::Fallback,809      // clang-format off810      MS(Abort,       Abort)811      MS(Default_Mem, Default_Mem)812      MS(Null,        Null)813      // clang-format on814  );815 816  auto &mods = semantics::OmpGetModifiers(inp.v);817  auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpAccessGroup>(mods);818  auto *m1 = semantics::OmpGetUniqueModifier<parser::OmpFallbackModifier>(mods);819  auto &size = std::get<parser::ScalarIntExpr>(inp.v.t);820 821  return DynGroupprivate{{/*AccessGroup=*/maybeApplyToV(makeAccessGroup, m0),822                          /*Fallback=*/maybeApplyToV(makeFallback, m1),823                          /*Size=*/makeExpr(size, semaCtx)}};824}825 826Enter make(const parser::OmpClause::Enter &inp,827           semantics::SemanticsContext &semaCtx) {828  // inp.v -> parser::OmpEnterClause829  CLAUSET_ENUM_CONVERT( //830      convert, parser::OmpAutomapModifier::Value, Enter::Modifier,831      // clang-format off832      MS(Automap, Automap)833      // clang-format on834  );835  auto &mods = semantics::OmpGetModifiers(inp.v);836  auto *mod = semantics::OmpGetUniqueModifier<parser::OmpAutomapModifier>(mods);837  auto &objList = std::get<parser::OmpObjectList>(inp.v.t);838 839  return Enter{{/*Modifier=*/maybeApplyToV(convert, mod),840                /*List=*/makeObjects(objList, semaCtx)}};841}842 843Exclusive make(const parser::OmpClause::Exclusive &inp,844               semantics::SemanticsContext &semaCtx) {845  // inp.v -> parser::OmpObjectList846  return Exclusive{makeObjects(/*List=*/inp.v, semaCtx)};847}848 849Fail make(const parser::OmpClause::Fail &inp,850          semantics::SemanticsContext &semaCtx) {851  // inp.v -> parser::OmpFalClause852  CLAUSET_ENUM_CONVERT( //853      convert, common::OmpMemoryOrderType, Fail::MemoryOrder,854      // clang-format off855      MS(Acq_Rel,  AcqRel)856      MS(Acquire,  Acquire)857      MS(Relaxed,  Relaxed)858      MS(Release,  Release)859      MS(Seq_Cst,  SeqCst)860      // clang-format on861  );862 863  return Fail{/*MemoryOrder=*/convert(inp.v.v)};864}865 866Filter make(const parser::OmpClause::Filter &inp,867            semantics::SemanticsContext &semaCtx) {868  // inp.v -> parser::ScalarIntExpr869  return Filter{/*ThreadNum=*/makeExpr(inp.v, semaCtx)};870}871 872Final make(const parser::OmpClause::Final &inp,873           semantics::SemanticsContext &semaCtx) {874  // inp.v -> parser::ScalarLogicalExpr875  return Final{/*Finalize=*/makeExpr(inp.v, semaCtx)};876}877 878Firstprivate make(const parser::OmpClause::Firstprivate &inp,879                  semantics::SemanticsContext &semaCtx) {880  // inp.v -> parser::OmpObjectList881  return Firstprivate{/*List=*/makeObjects(inp.v, semaCtx)};882}883 884// Flush: empty885 886From make(const parser::OmpClause::From &inp,887          semantics::SemanticsContext &semaCtx) {888  // inp.v -> parser::OmpFromClause889  CLAUSET_ENUM_CONVERT( //890      convert, parser::OmpExpectation::Value, From::Expectation,891      // clang-format off892      MS(Present, Present)893      // clang-format on894  );895 896  auto &mods = semantics::OmpGetModifiers(inp.v);897  auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);898  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);899  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);900  auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);901 902  auto mappers = [&]() -> std::optional<List<Mapper>> {903    if (t1)904      return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};905    return std::nullopt;906  }();907 908  auto iterator = [&]() -> std::optional<Iterator> {909    if (t2)910      return makeIterator(*t2, semaCtx);911    return std::nullopt;912  }();913 914  return From{{/*Expectation=*/maybeApplyToV(convert, t0),915               /*Mappers=*/std::move(mappers),916               /*Iterator=*/std::move(iterator),917               /*LocatorList=*/makeObjects(t3, semaCtx)}};918}919 920// Full: empty921 922Grainsize make(const parser::OmpClause::Grainsize &inp,923               semantics::SemanticsContext &semaCtx) {924  // inp.v -> parser::OmpGrainsizeClause925  auto &mods = semantics::OmpGetModifiers(inp.v);926  auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpPrescriptiveness>(mods);927  auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);928  return Grainsize{929      {/*Prescriptiveness=*/maybeApplyToV(makePrescriptiveness, m0),930       /*Grainsize=*/makeExpr(t1, semaCtx)}};931}932 933HasDeviceAddr make(const parser::OmpClause::HasDeviceAddr &inp,934                   semantics::SemanticsContext &semaCtx) {935  // inp.v -> parser::OmpObjectList936  return HasDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)};937}938 939Hint make(const parser::OmpClause::Hint &inp,940          semantics::SemanticsContext &semaCtx) {941  // inp.v -> parser::OmpHintClause942  return Hint{/*HintExpr=*/makeExpr(inp.v.v, semaCtx)};943}944 945Holds make(const parser::OmpClause::Holds &inp,946           semantics::SemanticsContext &semaCtx) {947  llvm_unreachable("Unimplemented: holds");948}949 950If make(const parser::OmpClause::If &inp,951        semantics::SemanticsContext &semaCtx) {952  // inp.v -> parser::OmpIfClause953  auto &mods = semantics::OmpGetModifiers(inp.v);954  auto *m0 =955      semantics::OmpGetUniqueModifier<parser::OmpDirectiveNameModifier>(mods);956  auto &t1 = std::get<parser::ScalarLogicalExpr>(inp.v.t);957  return If{958      {/*DirectiveNameModifier=*/maybeApplyToV([](auto &&s) { return s; }, m0),959       /*IfExpression=*/makeExpr(t1, semaCtx)}};960}961 962// Inbranch: empty963 964Inclusive make(const parser::OmpClause::Inclusive &inp,965               semantics::SemanticsContext &semaCtx) {966  // inp.v -> parser::OmpObjectList967  return Inclusive{makeObjects(/*List=*/inp.v, semaCtx)};968}969 970Indirect make(const parser::OmpClause::Indirect &inp,971              semantics::SemanticsContext &semaCtx) {972  // inp.v.v -> std::optional<parser::ScalarLogicalExpr>973  return Indirect{maybeApply(makeExprFn(semaCtx), inp.v.v)};974}975 976Init make(const parser::OmpClause::Init &inp,977          semantics::SemanticsContext &semaCtx) {978  // inp -> empty979  llvm_unreachable("Empty: init");980}981 982Initializer make(const parser::OmpClause::Initializer &inp,983                 semantics::SemanticsContext &semaCtx) {984  const parser::OmpInitializerExpression &iexpr = inp.v.v;985  const parser::OmpStylizedInstance &styleInstance = iexpr.v.front();986  const parser::OmpStylizedInstance::Instance &instance =987      std::get<parser::OmpStylizedInstance::Instance>(styleInstance.t);988  if (const auto *as = std::get_if<parser::AssignmentStmt>(&instance.u)) {989    auto &expr = std::get<parser::Expr>(as->t);990    return Initializer{makeExpr(expr, semaCtx)};991  } else if (const auto *call = std::get_if<parser::CallStmt>(&instance.u)) {992    if (call->typedCall) {993      const auto &procRef = *call->typedCall;994      semantics::SomeExpr evalProcRef{procRef};995      return Initializer{evalProcRef};996    }997  }998 999  llvm_unreachable("Unexpected initializer");1000}1001 1002InReduction make(const parser::OmpClause::InReduction &inp,1003                 semantics::SemanticsContext &semaCtx) {1004  // inp.v -> parser::OmpInReductionClause1005  auto &mods = semantics::OmpGetModifiers(inp.v);1006  auto *m0 =1007      semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods);1008  auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);1009  assert(m0 && "OmpReductionIdentifier is required");1010 1011  return InReduction{1012      {/*ReductionIdentifiers=*/{makeReductionOperator(*m0, semaCtx)},1013       /*List=*/makeObjects(t1, semaCtx)}};1014}1015 1016IsDevicePtr make(const parser::OmpClause::IsDevicePtr &inp,1017                 semantics::SemanticsContext &semaCtx) {1018  // inp.v -> parser::OmpObjectList1019  return IsDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)};1020}1021 1022Lastprivate make(const parser::OmpClause::Lastprivate &inp,1023                 semantics::SemanticsContext &semaCtx) {1024  // inp.v -> parser::OmpLastprivateClause1025  CLAUSET_ENUM_CONVERT( //1026      convert, parser::OmpLastprivateModifier::Value,1027      Lastprivate::LastprivateModifier,1028      // clang-format off1029      MS(Conditional, Conditional)1030      // clang-format on1031  );1032 1033  auto &mods = semantics::OmpGetModifiers(inp.v);1034  auto *m0 =1035      semantics::OmpGetUniqueModifier<parser::OmpLastprivateModifier>(mods);1036  auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);1037 1038  return Lastprivate{{/*LastprivateModifier=*/maybeApplyToV(convert, m0),1039                      /*List=*/makeObjects(t1, semaCtx)}};1040}1041 1042Linear make(const parser::OmpClause::Linear &inp,1043            semantics::SemanticsContext &semaCtx) {1044  // inp.v -> parser::OmpLinearClause1045  CLAUSET_ENUM_CONVERT( //1046      convert, parser::OmpLinearModifier::Value, Linear::LinearModifier,1047      // clang-format off1048      MS(Ref,  Ref)1049      MS(Val,  Val)1050      MS(Uval, Uval)1051      // clang-format on1052  );1053 1054  auto &mods = semantics::OmpGetModifiers(inp.v);1055  auto *m0 =1056      semantics::OmpGetUniqueModifier<parser::OmpStepComplexModifier>(mods);1057  auto *m1 =1058      semantics::OmpGetUniqueModifier<parser::OmpStepSimpleModifier>(mods);1059  assert((!m0 || !m1) && "Simple and complex modifiers both present");1060 1061  auto *m2 = semantics::OmpGetUniqueModifier<parser::OmpLinearModifier>(mods);1062  auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);1063 1064  auto &&maybeStep = m0   ? maybeApplyToV(makeExprFn(semaCtx), m0)1065                     : m1 ? maybeApplyToV(makeExprFn(semaCtx), m1)1066                          : std::optional<Linear::StepComplexModifier>{};1067 1068  return Linear{{/*StepComplexModifier=*/std::move(maybeStep),1069                 /*LinearModifier=*/maybeApplyToV(convert, m2),1070                 /*List=*/makeObjects(t1, semaCtx)}};1071}1072 1073Link make(const parser::OmpClause::Link &inp,1074          semantics::SemanticsContext &semaCtx) {1075  // inp.v -> parser::OmpObjectList1076  return Link{/*List=*/makeObjects(inp.v, semaCtx)};1077}1078 1079LoopRange make(const parser::OmpClause::Looprange &inp,1080               semantics::SemanticsContext &semaCtx) {1081  llvm_unreachable("Unimplemented: looprange");1082}1083 1084Map make(const parser::OmpClause::Map &inp,1085         semantics::SemanticsContext &semaCtx) {1086  // inp.v -> parser::OmpMapClause1087  CLAUSET_ENUM_CONVERT( //1088      convertMapType, parser::OmpMapType::Value, Map::MapType,1089      // clang-format off1090      MS(Alloc,   Storage)1091      MS(Delete,  Storage)1092      MS(Release, Storage)1093      MS(Storage, Storage)1094      MS(From,    From)1095      MS(To,      To)1096      MS(Tofrom,  Tofrom)1097      // clang-format on1098  );1099 1100  CLAUSET_ENUM_CONVERT( //1101      convertMapTypeMod, parser::OmpMapTypeModifier::Value,1102      Map::MapTypeModifier,1103      // clang-format off1104      MS(Always,    Always)1105      MS(Close,     Close)1106      MS(Ompx_Hold, OmpxHold)1107      MS(Present,   Present)1108      // clang-format on1109  );1110 1111  CLAUSET_ENUM_CONVERT( //1112      convertAttachMod, parser::OmpAttachModifier::Value, Map::AttachModifier,1113      // clang-format off1114      MS(Always,  Always)1115      MS(Auto,    Auto)1116      MS(Never,   Never)1117      // clang-format on1118  );1119 1120  CLAUSET_ENUM_CONVERT( //1121      convertRefMod, parser::OmpRefModifier::Value, Map::RefModifier,1122      // clang-format off1123      MS(Ref_Ptee,     RefPtee)1124      MS(Ref_Ptr,      RefPtr)1125      MS(Ref_Ptr_Ptee, RefPtrPtee)1126      // clang-format on1127  );1128 1129  // Treat always, close, present, self, delete modifiers as map-type-1130  // modifiers.1131  auto &mods = semantics::OmpGetModifiers(inp.v);1132 1133  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapType>(mods);1134  auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);1135 1136  auto type = [&]() -> std::optional<Map::MapType> {1137    if (t1)1138      return convertMapType(t1->v);1139    return std::nullopt;1140  }();1141 1142  llvm::DenseSet<Map::MapTypeModifier> modSet;1143  if (t1 && t1->v == parser::OmpMapType::Value::Delete)1144    modSet.insert(Map::MapTypeModifier::Delete);1145 1146  for (auto *typeMod :1147       semantics::OmpGetRepeatableModifier<parser::OmpMapTypeModifier>(mods)) {1148    modSet.insert(convertMapTypeMod(typeMod->v));1149  }1150  if (semantics::OmpGetUniqueModifier<parser::OmpAlwaysModifier>(mods))1151    modSet.insert(Map::MapTypeModifier::Always);1152  if (semantics::OmpGetUniqueModifier<parser::OmpCloseModifier>(mods))1153    modSet.insert(Map::MapTypeModifier::Close);1154  if (semantics::OmpGetUniqueModifier<parser::OmpDeleteModifier>(mods))1155    modSet.insert(Map::MapTypeModifier::Delete);1156  if (semantics::OmpGetUniqueModifier<parser::OmpPresentModifier>(mods))1157    modSet.insert(Map::MapTypeModifier::Present);1158  if (semantics::OmpGetUniqueModifier<parser::OmpSelfModifier>(mods))1159    modSet.insert(Map::MapTypeModifier::Self);1160  if (semantics::OmpGetUniqueModifier<parser::OmpxHoldModifier>(mods))1161    modSet.insert(Map::MapTypeModifier::OmpxHold);1162 1163  std::optional<Map::MapTypeModifiers> maybeTypeMods{};1164  if (!modSet.empty())1165    maybeTypeMods = Map::MapTypeModifiers(modSet.begin(), modSet.end());1166 1167  auto attachMod = [&]() -> std::optional<Map::AttachModifier> {1168    if (auto *t =1169            semantics::OmpGetUniqueModifier<parser::OmpAttachModifier>(mods))1170      return convertAttachMod(t->v);1171    return std::nullopt;1172  }();1173 1174  auto refMod = [&]() -> std::optional<Map::RefModifier> {1175    if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpRefModifier>(mods))1176      return convertRefMod(t->v);1177    return std::nullopt;1178  }();1179 1180  auto mappers = [&]() -> std::optional<List<Mapper>> {1181    if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods))1182      return List<Mapper>{Mapper{makeObject(t->v, semaCtx)}};1183    return std::nullopt;1184  }();1185 1186  auto iterator = [&]() -> std::optional<Iterator> {1187    if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods))1188      return makeIterator(*t, semaCtx);1189    return std::nullopt;1190  }();1191 1192  return Map{{/*MapType=*/std::move(type),1193              /*MapTypeModifiers=*/std::move(maybeTypeMods),1194              /*AttachModifier=*/std::move(attachMod),1195              /*RefModifier=*/std::move(refMod), /*Mapper=*/std::move(mappers),1196              /*Iterator=*/std::move(iterator),1197              /*LocatorList=*/makeObjects(t2, semaCtx)}};1198}1199 1200Match make(const parser::OmpClause::Match &inp,1201           semantics::SemanticsContext &semaCtx) {1202  return Match{};1203}1204 1205// MemoryOrder: empty1206// Mergeable: empty1207 1208Message make(const parser::OmpClause::Message &inp,1209             semantics::SemanticsContext &semaCtx) {1210  // inp -> empty1211  llvm_unreachable("Empty: message");1212}1213 1214Nocontext make(const parser::OmpClause::Nocontext &inp,1215               semantics::SemanticsContext &semaCtx) {1216  // inp.v -> parser::ScalarLogicalExpr1217  return Nocontext{/*DoNotUpdateContext=*/makeExpr(inp.v, semaCtx)};1218}1219 1220// Nogroup: empty1221 1222Nontemporal make(const parser::OmpClause::Nontemporal &inp,1223                 semantics::SemanticsContext &semaCtx) {1224  // inp.v -> std::list<parser::Name>1225  return Nontemporal{/*List=*/makeList(inp.v, makeObjectFn(semaCtx))};1226}1227 1228// NoOpenmp: empty1229// NoOpenmpRoutines: empty1230// NoOpenmpConstructs: empty1231// NoParallelism: empty1232// Notinbranch: empty1233 1234Novariants make(const parser::OmpClause::Novariants &inp,1235                semantics::SemanticsContext &semaCtx) {1236  // inp.v -> parser::ScalarLogicalExpr1237  return Novariants{/*DoNotUseVariant=*/makeExpr(inp.v, semaCtx)};1238}1239 1240// Nowait: empty1241 1242NumTasks make(const parser::OmpClause::NumTasks &inp,1243              semantics::SemanticsContext &semaCtx) {1244  // inp.v -> parser::OmpNumTasksClause1245  auto &mods = semantics::OmpGetModifiers(inp.v);1246  auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpPrescriptiveness>(mods);1247  auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);1248  return NumTasks{{/*Prescriptiveness=*/maybeApplyToV(makePrescriptiveness, m0),1249                   /*NumTasks=*/makeExpr(t1, semaCtx)}};1250}1251 1252NumTeams make(const parser::OmpClause::NumTeams &inp,1253              semantics::SemanticsContext &semaCtx) {1254  // inp.v -> parser::ScalarIntExpr1255  List<NumTeams::Range> v{{{/*LowerBound=*/std::nullopt,1256                            /*UpperBound=*/makeExpr(inp.v, semaCtx)}}};1257  return NumTeams{/*List=*/v};1258}1259 1260NumThreads make(const parser::OmpClause::NumThreads &inp,1261                semantics::SemanticsContext &semaCtx) {1262  // inp.v -> parser::ScalarIntExpr1263  return NumThreads{/*Nthreads=*/makeExpr(inp.v, semaCtx)};1264}1265 1266// OmpxAttribute: empty1267// OmpxBare: empty1268 1269OmpxDynCgroupMem make(const parser::OmpClause::OmpxDynCgroupMem &inp,1270                      semantics::SemanticsContext &semaCtx) {1271  // inp.v -> parser::ScalarIntExpr1272  return OmpxDynCgroupMem{makeExpr(inp.v, semaCtx)};1273}1274 1275Order make(const parser::OmpClause::Order &inp,1276           semantics::SemanticsContext &semaCtx) {1277  // inp.v -> parser::OmpOrderClause1278  using wrapped = parser::OmpOrderClause;1279 1280  CLAUSET_ENUM_CONVERT( //1281      convert1, parser::OmpOrderModifier::Value, Order::OrderModifier,1282      // clang-format off1283      MS(Reproducible,   Reproducible)1284      MS(Unconstrained,  Unconstrained)1285      // clang-format on1286  );1287 1288  CLAUSET_ENUM_CONVERT( //1289      convert2, wrapped::Ordering, Order::Ordering,1290      // clang-format off1291      MS(Concurrent, Concurrent)1292      // clang-format on1293  );1294 1295  auto &mods = semantics::OmpGetModifiers(inp.v);1296  auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpOrderModifier>(mods);1297  auto &t1 = std::get<wrapped::Ordering>(inp.v.t);1298 1299  return Order{{/*OrderModifier=*/maybeApplyToV(convert1, t0),1300                /*Ordering=*/convert2(t1)}};1301}1302 1303Ordered make(const parser::OmpClause::Ordered &inp,1304             semantics::SemanticsContext &semaCtx) {1305  // inp.v -> std::optional<parser::ScalarIntConstantExpr>1306  return Ordered{/*N=*/maybeApply(makeExprFn(semaCtx), inp.v)};1307}1308 1309// See also Default.1310Otherwise make(const parser::OmpClause::Otherwise &inp,1311               semantics::SemanticsContext &semaCtx) {1312  return Otherwise{};1313}1314 1315Partial make(const parser::OmpClause::Partial &inp,1316             semantics::SemanticsContext &semaCtx) {1317  // inp.v -> std::optional<parser::ScalarIntConstantExpr>1318  return Partial{/*UnrollFactor=*/maybeApply(makeExprFn(semaCtx), inp.v)};1319}1320 1321Priority make(const parser::OmpClause::Priority &inp,1322              semantics::SemanticsContext &semaCtx) {1323  // inp.v -> parser::ScalarIntExpr1324  return Priority{/*PriorityValue=*/makeExpr(inp.v, semaCtx)};1325}1326 1327Private make(const parser::OmpClause::Private &inp,1328             semantics::SemanticsContext &semaCtx) {1329  // inp.v -> parser::OmpObjectList1330  return Private{/*List=*/makeObjects(inp.v, semaCtx)};1331}1332 1333ProcBind make(const parser::OmpClause::ProcBind &inp,1334              semantics::SemanticsContext &semaCtx) {1335  // inp.v -> parser::OmpProcBindClause1336  using wrapped = parser::OmpProcBindClause;1337 1338  CLAUSET_ENUM_CONVERT( //1339      convert, wrapped::AffinityPolicy, ProcBind::AffinityPolicy,1340      // clang-format off1341      MS(Close,    Close)1342      MS(Master,   Master)1343      MS(Spread,   Spread)1344      MS(Primary,  Primary)1345      // clang-format on1346  );1347  return ProcBind{/*AffinityPolicy=*/convert(inp.v.v)};1348}1349 1350// Read: empty1351 1352Reduction make(const parser::OmpClause::Reduction &inp,1353               semantics::SemanticsContext &semaCtx) {1354  // inp.v -> parser::OmpReductionClause1355  CLAUSET_ENUM_CONVERT( //1356      convert, parser::OmpReductionModifier::Value,1357      Reduction::ReductionModifier,1358      // clang-format off1359      MS(Inscan,  Inscan)1360      MS(Task,    Task)1361      MS(Default, Default)1362      // clang-format on1363  );1364 1365  auto &mods = semantics::OmpGetModifiers(inp.v);1366  auto *m0 =1367      semantics::OmpGetUniqueModifier<parser::OmpReductionModifier>(mods);1368  auto *m1 =1369      semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods);1370  auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);1371  assert(m1 && "OmpReductionIdentifier is required");1372 1373  return Reduction{1374      {/*ReductionModifier=*/maybeApplyToV(convert, m0),1375       /*ReductionIdentifiers=*/{makeReductionOperator(*m1, semaCtx)},1376       /*List=*/makeObjects(t1, semaCtx)}};1377}1378 1379// Relaxed: empty1380// Release: empty1381 1382ReverseOffload make(const parser::OmpClause::ReverseOffload &inp,1383                    semantics::SemanticsContext &semaCtx) {1384  // inp.v -> std::optional<parser::OmpReverseOffloadClause>1385  auto &&maybeRequired = maybeApply(1386      [&](const parser::OmpReverseOffloadClause &c) {1387        return makeExpr(c.v, semaCtx);1388      },1389      inp.v);1390 1391  return ReverseOffload{/*Required=*/std::move(maybeRequired)};1392}1393 1394Safelen make(const parser::OmpClause::Safelen &inp,1395             semantics::SemanticsContext &semaCtx) {1396  // inp.v -> parser::ScalarIntConstantExpr1397  return Safelen{/*Length=*/makeExpr(inp.v, semaCtx)};1398}1399 1400Schedule make(const parser::OmpClause::Schedule &inp,1401              semantics::SemanticsContext &semaCtx) {1402  // inp.v -> parser::OmpScheduleClause1403  using wrapped = parser::OmpScheduleClause;1404 1405  CLAUSET_ENUM_CONVERT( //1406      convert1, wrapped::Kind, Schedule::Kind,1407      // clang-format off1408      MS(Static,   Static)1409      MS(Dynamic,  Dynamic)1410      MS(Guided,   Guided)1411      MS(Auto,     Auto)1412      MS(Runtime,  Runtime)1413      // clang-format on1414  );1415 1416  CLAUSET_ENUM_CONVERT( //1417      convert2, parser::OmpOrderingModifier::Value, Schedule::OrderingModifier,1418      // clang-format off1419      MS(Monotonic,    Monotonic)1420      MS(Nonmonotonic, Nonmonotonic)1421      // clang-format on1422  );1423 1424  CLAUSET_ENUM_CONVERT( //1425      convert3, parser::OmpChunkModifier::Value, Schedule::ChunkModifier,1426      // clang-format off1427      MS(Simd, Simd)1428      // clang-format on1429  );1430 1431  auto &mods = semantics::OmpGetModifiers(inp.v);1432  auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpOrderingModifier>(mods);1433  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpChunkModifier>(mods);1434  auto &t2 = std::get<wrapped::Kind>(inp.v.t);1435  auto &t3 = std::get<std::optional<parser::ScalarIntExpr>>(inp.v.t);1436 1437  return Schedule{{/*Kind=*/convert1(t2),1438                   /*OrderingModifier=*/maybeApplyToV(convert2, t0),1439                   /*ChunkModifier=*/maybeApplyToV(convert3, t1),1440                   /*ChunkSize=*/maybeApply(makeExprFn(semaCtx), t3)}};1441}1442 1443// SeqCst: empty1444 1445SelfMaps make(const parser::OmpClause::SelfMaps &inp,1446              semantics::SemanticsContext &semaCtx) {1447  // inp.v -> std::optional<parser::OmpSelfMapsClause>1448  auto &&maybeRequired = maybeApply(1449      [&](const parser::OmpSelfMapsClause &c) {1450        return makeExpr(c.v, semaCtx);1451      },1452      inp.v);1453 1454  return SelfMaps{/*Required=*/std::move(maybeRequired)};1455}1456 1457Severity make(const parser::OmpClause::Severity &inp,1458              semantics::SemanticsContext &semaCtx) {1459  // inp -> empty1460  llvm_unreachable("Empty: severity");1461}1462 1463Shared make(const parser::OmpClause::Shared &inp,1464            semantics::SemanticsContext &semaCtx) {1465  // inp.v -> parser::OmpObjectList1466  return Shared{/*List=*/makeObjects(inp.v, semaCtx)};1467}1468 1469// Simd: empty1470 1471Simdlen make(const parser::OmpClause::Simdlen &inp,1472             semantics::SemanticsContext &semaCtx) {1473  // inp.v -> parser::ScalarIntConstantExpr1474  return Simdlen{/*Length=*/makeExpr(inp.v, semaCtx)};1475}1476 1477Sizes make(const parser::OmpClause::Sizes &inp,1478           semantics::SemanticsContext &semaCtx) {1479  // inp.v -> std::list<parser::ScalarIntExpr>1480  return Sizes{/*SizeList=*/makeList(inp.v, makeExprFn(semaCtx))};1481}1482 1483Permutation make(const parser::OmpClause::Permutation &inp,1484                 semantics::SemanticsContext &semaCtx) {1485  // inp.v -> std::list<parser::ScalarIntConstantExpr>1486  return Permutation{/*ArgList=*/makeList(inp.v, makeExprFn(semaCtx))};1487}1488 1489TaskReduction make(const parser::OmpClause::TaskReduction &inp,1490                   semantics::SemanticsContext &semaCtx) {1491  // inp.v -> parser::OmpReductionClause1492  auto &mods = semantics::OmpGetModifiers(inp.v);1493  auto *m0 =1494      semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods);1495  auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);1496  assert(m0 && "OmpReductionIdentifier is required");1497 1498  return TaskReduction{1499      {/*ReductionIdentifiers=*/{makeReductionOperator(*m0, semaCtx)},1500       /*List=*/makeObjects(t1, semaCtx)}};1501}1502 1503ThreadLimit make(const parser::OmpClause::ThreadLimit &inp,1504                 semantics::SemanticsContext &semaCtx) {1505  // inp.v -> parser::ScalarIntExpr1506  return ThreadLimit{/*Threadlim=*/makeExpr(inp.v, semaCtx)};1507}1508 1509Threadset make(const parser::OmpClause::Threadset &inp,1510               semantics::SemanticsContext &semaCtx) {1511  // inp.v -> parser::OmpThreadsetClause1512  using wrapped = parser::OmpThreadsetClause;1513 1514  CLAUSET_ENUM_CONVERT( //1515      convert, wrapped::ThreadsetPolicy, Threadset::ThreadsetPolicy,1516      // clang-format off1517      MS(Omp_Pool, Omp_Pool)1518      MS(Omp_Team, Omp_Team)1519      // clang-format on1520  );1521  return Threadset{/*ThreadsetPolicy=*/convert(inp.v.v)};1522}1523 1524// Threadprivate: empty1525// Threads: empty1526 1527To make(const parser::OmpClause::To &inp,1528        semantics::SemanticsContext &semaCtx) {1529  // inp.v -> parser::OmpToClause1530  CLAUSET_ENUM_CONVERT( //1531      convert, parser::OmpExpectation::Value, To::Expectation,1532      // clang-format off1533      MS(Present, Present)1534      // clang-format on1535  );1536 1537  auto &mods = semantics::OmpGetModifiers(inp.v);1538  auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);1539  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);1540  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);1541  auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);1542 1543  auto mappers = [&]() -> std::optional<List<Mapper>> {1544    if (t1)1545      return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};1546    return std::nullopt;1547  }();1548 1549  auto iterator = [&]() -> std::optional<Iterator> {1550    if (t2)1551      return makeIterator(*t2, semaCtx);1552    return std::nullopt;1553  }();1554 1555  return To{{/*Expectation=*/maybeApplyToV(convert, t0),1556             /*Mappers=*/{std::move(mappers)},1557             /*Iterator=*/std::move(iterator),1558             /*LocatorList=*/makeObjects(t3, semaCtx)}};1559}1560 1561UnifiedAddress make(const parser::OmpClause::UnifiedAddress &inp,1562                    semantics::SemanticsContext &semaCtx) {1563  // inp.v -> std::optional<parser::OmpUnifiedAddressClause>1564  auto &&maybeRequired = maybeApply(1565      [&](const parser::OmpUnifiedAddressClause &c) {1566        return makeExpr(c.v, semaCtx);1567      },1568      inp.v);1569 1570  return UnifiedAddress{/*Required=*/std::move(maybeRequired)};1571}1572 1573UnifiedSharedMemory make(const parser::OmpClause::UnifiedSharedMemory &inp,1574                         semantics::SemanticsContext &semaCtx) {1575  // inp.v -> std::optional<parser::OmpUnifiedSharedMemoryClause>1576  auto &&maybeRequired = maybeApply(1577      [&](const parser::OmpUnifiedSharedMemoryClause &c) {1578        return makeExpr(c.v, semaCtx);1579      },1580      inp.v);1581 1582  return UnifiedSharedMemory{/*Required=*/std::move(maybeRequired)};1583}1584 1585Uniform make(const parser::OmpClause::Uniform &inp,1586             semantics::SemanticsContext &semaCtx) {1587  // inp.v -> std::list<parser::Name>1588  return Uniform{/*ParameterList=*/makeList(inp.v, makeObjectFn(semaCtx))};1589}1590 1591// Unknown: empty1592// Untied: empty1593 1594Update make(const parser::OmpClause::Update &inp,1595            semantics::SemanticsContext &semaCtx) {1596  // inp.v -> parser::OmpUpdateClause1597  if (inp.v) {1598    return common::visit(1599        [](auto &&s) { return Update{/*DependenceType=*/makeDepType(s)}; },1600        inp.v->u);1601  } else {1602    return Update{/*DependenceType=*/std::nullopt};1603  }1604}1605 1606Use make(const parser::OmpClause::Use &inp,1607         semantics::SemanticsContext &semaCtx) {1608  // inp -> empty1609  llvm_unreachable("Empty: use");1610}1611 1612UseDeviceAddr make(const parser::OmpClause::UseDeviceAddr &inp,1613                   semantics::SemanticsContext &semaCtx) {1614  // inp.v -> parser::OmpObjectList1615  return UseDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)};1616}1617 1618UseDevicePtr make(const parser::OmpClause::UseDevicePtr &inp,1619                  semantics::SemanticsContext &semaCtx) {1620  // inp.v -> parser::OmpObjectList1621  return UseDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)};1622}1623 1624UsesAllocators make(const parser::OmpClause::UsesAllocators &inp,1625                    semantics::SemanticsContext &semaCtx) {1626  // inp -> empty1627  llvm_unreachable("Empty: uses_allocators");1628}1629 1630// Weak: empty1631 1632When make(const parser::OmpClause::When &inp,1633          semantics::SemanticsContext &semaCtx) {1634  return When{};1635}1636 1637// Write: empty1638} // namespace clause1639 1640Clause makeClause(const parser::OmpClause &cls,1641                  semantics::SemanticsContext &semaCtx) {1642  return Fortran::common::visit( //1643      common::visitors{1644          [&](const parser::OmpClause::Default &s) {1645            using DSA = parser::OmpDefaultClause::DataSharingAttribute;1646            if (std::holds_alternative<DSA>(s.v.u)) {1647              return makeClause(llvm::omp::Clause::OMPC_default,1648                                clause::makeDefault(s, semaCtx), cls.source);1649            } else {1650              return makeClause(llvm::omp::Clause::OMPC_otherwise,1651                                clause::makeOtherwise(s, semaCtx), cls.source);1652            }1653          },1654          [&](auto &&s) {1655            return makeClause(cls.Id(), clause::make(s, semaCtx), cls.source);1656          },1657      },1658      cls.u);1659}1660 1661List<Clause> makeClauses(const parser::OmpClauseList &clauses,1662                         semantics::SemanticsContext &semaCtx) {1663  return makeList(clauses.v, [&](const parser::OmpClause &s) {1664    return makeClause(s, semaCtx);1665  });1666}1667 1668bool transferLocations(const List<Clause> &from, List<Clause> &to) {1669  bool allDone = true;1670 1671  for (Clause &clause : to) {1672    if (!clause.source.empty())1673      continue;1674    auto found =1675        llvm::find_if(from, [&](const Clause &c) { return c.id == clause.id; });1676    // This is not completely accurate, but should be good enough for now.1677    // It can be improved in the future if necessary, but in cases of1678    // synthesized clauses getting accurate location may be impossible.1679    if (found != from.end()) {1680      clause.source = found->source;1681    } else {1682      // Found a clause that won't have "source".1683      allDone = false;1684    }1685  }1686 1687  return allDone;1688}1689 1690} // namespace Fortran::lower::omp1691