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