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