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