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