1 //===----------------------------------------------------------------------===// 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 "resolve-directives.h" 10 11 #include "check-acc-structure.h" 12 #include "check-omp-structure.h" 13 #include "resolve-names-utils.h" 14 #include "flang/Common/idioms.h" 15 #include "flang/Evaluate/fold.h" 16 #include "flang/Evaluate/type.h" 17 #include "flang/Parser/parse-tree-visitor.h" 18 #include "flang/Parser/parse-tree.h" 19 #include "flang/Parser/tools.h" 20 #include "flang/Semantics/expression.h" 21 #include <list> 22 #include <map> 23 24 namespace Fortran::semantics { 25 26 template <typename T> class DirectiveAttributeVisitor { 27 public: 28 explicit DirectiveAttributeVisitor(SemanticsContext &context) 29 : context_{context} {} 30 31 template <typename A> bool Pre(const A &) { return true; } 32 template <typename A> void Post(const A &) {} 33 34 protected: 35 struct DirContext { 36 DirContext(const parser::CharBlock &source, T d, Scope &s) 37 : directiveSource{source}, directive{d}, scope{s} {} 38 parser::CharBlock directiveSource; 39 T directive; 40 Scope &scope; 41 Symbol::Flag defaultDSA{Symbol::Flag::AccShared}; // TODOACC 42 std::map<const Symbol *, Symbol::Flag> objectWithDSA; 43 bool withinConstruct{false}; 44 std::int64_t associatedLoopLevel{0}; 45 }; 46 47 DirContext &GetContext() { 48 CHECK(!dirContext_.empty()); 49 return dirContext_.back(); 50 } 51 void PushContext(const parser::CharBlock &source, T dir) { 52 dirContext_.emplace_back(source, dir, context_.FindScope(source)); 53 } 54 void PopContext() { dirContext_.pop_back(); } 55 void SetContextDirectiveSource(parser::CharBlock &dir) { 56 GetContext().directiveSource = dir; 57 } 58 Scope &currScope() { return GetContext().scope; } 59 void SetContextDefaultDSA(Symbol::Flag flag) { 60 GetContext().defaultDSA = flag; 61 } 62 void AddToContextObjectWithDSA( 63 const Symbol &symbol, Symbol::Flag flag, DirContext &context) { 64 context.objectWithDSA.emplace(&symbol, flag); 65 } 66 void AddToContextObjectWithDSA(const Symbol &symbol, Symbol::Flag flag) { 67 AddToContextObjectWithDSA(symbol, flag, GetContext()); 68 } 69 bool IsObjectWithDSA(const Symbol &symbol) { 70 auto it{GetContext().objectWithDSA.find(&symbol)}; 71 return it != GetContext().objectWithDSA.end(); 72 } 73 void SetContextAssociatedLoopLevel(std::int64_t level) { 74 GetContext().associatedLoopLevel = level; 75 } 76 Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev, Scope &scope) { 77 const auto pair{scope.try_emplace(name, Attrs{}, HostAssocDetails{prev})}; 78 return *pair.first->second; 79 } 80 Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev) { 81 return MakeAssocSymbol(name, prev, currScope()); 82 } 83 static const parser::Name *GetDesignatorNameIfDataRef( 84 const parser::Designator &designator) { 85 const auto *dataRef{std::get_if<parser::DataRef>(&designator.u)}; 86 return dataRef ? std::get_if<parser::Name>(&dataRef->u) : nullptr; 87 } 88 void AddDataSharingAttributeObject(SymbolRef object) { 89 dataSharingAttributeObjects_.insert(object); 90 } 91 void ClearDataSharingAttributeObjects() { 92 dataSharingAttributeObjects_.clear(); 93 } 94 bool HasDataSharingAttributeObject(const Symbol &); 95 const parser::Name &GetLoopIndex(const parser::DoConstruct &); 96 const parser::DoConstruct *GetDoConstructIf( 97 const parser::ExecutionPartConstruct &); 98 Symbol *DeclarePrivateAccessEntity( 99 const parser::Name &, Symbol::Flag, Scope &); 100 Symbol *DeclarePrivateAccessEntity(Symbol &, Symbol::Flag, Scope &); 101 Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag); 102 103 SymbolSet dataSharingAttributeObjects_; // on one directive 104 SemanticsContext &context_; 105 std::vector<DirContext> dirContext_; // used as a stack 106 }; 107 108 class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> { 109 public: 110 explicit AccAttributeVisitor(SemanticsContext &context) 111 : DirectiveAttributeVisitor(context) {} 112 113 template <typename A> void Walk(const A &x) { parser::Walk(x, *this); } 114 template <typename A> bool Pre(const A &) { return true; } 115 template <typename A> void Post(const A &) {} 116 117 bool Pre(const parser::OpenACCBlockConstruct &); 118 void Post(const parser::OpenACCBlockConstruct &) { PopContext(); } 119 bool Pre(const parser::OpenACCCombinedConstruct &); 120 void Post(const parser::OpenACCCombinedConstruct &) { PopContext(); } 121 122 bool Pre(const parser::OpenACCDeclarativeConstruct &); 123 void Post(const parser::OpenACCDeclarativeConstruct &) { PopContext(); } 124 125 bool Pre(const parser::OpenACCRoutineConstruct &); 126 bool Pre(const parser::AccBindClause &); 127 void Post(const parser::OpenACCStandaloneDeclarativeConstruct &); 128 129 void Post(const parser::AccBeginBlockDirective &) { 130 GetContext().withinConstruct = true; 131 } 132 133 bool Pre(const parser::OpenACCLoopConstruct &); 134 void Post(const parser::OpenACCLoopConstruct &) { PopContext(); } 135 void Post(const parser::AccLoopDirective &) { 136 GetContext().withinConstruct = true; 137 } 138 139 bool Pre(const parser::OpenACCStandaloneConstruct &); 140 void Post(const parser::OpenACCStandaloneConstruct &) { PopContext(); } 141 void Post(const parser::AccStandaloneDirective &) { 142 GetContext().withinConstruct = true; 143 } 144 145 bool Pre(const parser::OpenACCCacheConstruct &); 146 void Post(const parser::OpenACCCacheConstruct &) { PopContext(); } 147 148 void Post(const parser::AccDefaultClause &); 149 150 bool Pre(const parser::AccClause::Copy &x) { 151 ResolveAccObjectList(x.v, Symbol::Flag::AccCopyIn); 152 ResolveAccObjectList(x.v, Symbol::Flag::AccCopyOut); 153 return false; 154 } 155 156 bool Pre(const parser::AccClause::Create &x) { 157 const auto &objectList{std::get<parser::AccObjectList>(x.v.t)}; 158 ResolveAccObjectList(objectList, Symbol::Flag::AccCreate); 159 return false; 160 } 161 162 bool Pre(const parser::AccClause::Copyin &x) { 163 const auto &objectList{std::get<parser::AccObjectList>(x.v.t)}; 164 ResolveAccObjectList(objectList, Symbol::Flag::AccCopyIn); 165 return false; 166 } 167 168 bool Pre(const parser::AccClause::Copyout &x) { 169 const auto &objectList{std::get<parser::AccObjectList>(x.v.t)}; 170 ResolveAccObjectList(objectList, Symbol::Flag::AccCopyOut); 171 return false; 172 } 173 174 bool Pre(const parser::AccClause::Present &x) { 175 ResolveAccObjectList(x.v, Symbol::Flag::AccPresent); 176 return false; 177 } 178 bool Pre(const parser::AccClause::Private &x) { 179 ResolveAccObjectList(x.v, Symbol::Flag::AccPrivate); 180 return false; 181 } 182 bool Pre(const parser::AccClause::Firstprivate &x) { 183 ResolveAccObjectList(x.v, Symbol::Flag::AccFirstPrivate); 184 return false; 185 } 186 187 void Post(const parser::Name &); 188 189 private: 190 std::int64_t GetAssociatedLoopLevelFromClauses(const parser::AccClauseList &); 191 192 static constexpr Symbol::Flags dataSharingAttributeFlags{ 193 Symbol::Flag::AccShared, Symbol::Flag::AccPrivate, 194 Symbol::Flag::AccPresent, Symbol::Flag::AccFirstPrivate, 195 Symbol::Flag::AccReduction}; 196 197 static constexpr Symbol::Flags dataMappingAttributeFlags{ 198 Symbol::Flag::AccCreate, Symbol::Flag::AccCopyIn, 199 Symbol::Flag::AccCopyOut, Symbol::Flag::AccDelete}; 200 201 static constexpr Symbol::Flags accFlagsRequireNewSymbol{ 202 Symbol::Flag::AccPrivate, Symbol::Flag::AccFirstPrivate, 203 Symbol::Flag::AccReduction}; 204 205 static constexpr Symbol::Flags accFlagsRequireMark{}; 206 207 void PrivatizeAssociatedLoopIndex(const parser::OpenACCLoopConstruct &); 208 void ResolveAccObjectList(const parser::AccObjectList &, Symbol::Flag); 209 void ResolveAccObject(const parser::AccObject &, Symbol::Flag); 210 Symbol *ResolveAcc(const parser::Name &, Symbol::Flag, Scope &); 211 Symbol *ResolveAcc(Symbol &, Symbol::Flag, Scope &); 212 Symbol *ResolveName(const parser::Name &); 213 Symbol *ResolveAccCommonBlockName(const parser::Name *); 214 Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag); 215 Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag); 216 void CheckMultipleAppearances( 217 const parser::Name &, const Symbol &, Symbol::Flag); 218 void AllowOnlyArrayAndSubArray(const parser::AccObjectList &objectList); 219 void DoNotAllowAssumedSizedArray(const parser::AccObjectList &objectList); 220 }; 221 222 // Data-sharing and Data-mapping attributes for data-refs in OpenMP construct 223 class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> { 224 public: 225 explicit OmpAttributeVisitor(SemanticsContext &context) 226 : DirectiveAttributeVisitor(context) {} 227 228 template <typename A> void Walk(const A &x) { parser::Walk(x, *this); } 229 template <typename A> bool Pre(const A &) { return true; } 230 template <typename A> void Post(const A &) {} 231 232 bool Pre(const parser::SpecificationPart &x) { 233 Walk(std::get<std::list<parser::OpenMPDeclarativeConstruct>>(x.t)); 234 return true; 235 } 236 237 bool Pre(const parser::StmtFunctionStmt &x) { 238 const auto &parsedExpr{std::get<parser::Scalar<parser::Expr>>(x.t)}; 239 if (const auto *expr{GetExpr(parsedExpr)}) { 240 for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) { 241 if (!IsStmtFunctionDummy(symbol)) { 242 stmtFunctionExprSymbols_.insert(symbol.GetUltimate()); 243 } 244 } 245 } 246 return true; 247 } 248 249 bool Pre(const parser::OpenMPBlockConstruct &); 250 void Post(const parser::OpenMPBlockConstruct &); 251 252 void Post(const parser::OmpBeginBlockDirective &) { 253 GetContext().withinConstruct = true; 254 } 255 256 bool Pre(const parser::OpenMPLoopConstruct &); 257 void Post(const parser::OpenMPLoopConstruct &) { PopContext(); } 258 void Post(const parser::OmpBeginLoopDirective &) { 259 GetContext().withinConstruct = true; 260 } 261 bool Pre(const parser::DoConstruct &); 262 263 bool Pre(const parser::OpenMPSectionsConstruct &); 264 void Post(const parser::OpenMPSectionsConstruct &) { PopContext(); } 265 266 bool Pre(const parser::OpenMPDeclareSimdConstruct &x) { 267 PushContext(x.source, llvm::omp::Directive::OMPD_declare_simd); 268 const auto &name{std::get<std::optional<parser::Name>>(x.t)}; 269 if (name) { 270 ResolveOmpName(*name, Symbol::Flag::OmpDeclareSimd); 271 } 272 return true; 273 } 274 void Post(const parser::OpenMPDeclareSimdConstruct &) { PopContext(); } 275 bool Pre(const parser::OpenMPThreadprivate &); 276 void Post(const parser::OpenMPThreadprivate &) { PopContext(); } 277 278 // 2.15.3 Data-Sharing Attribute Clauses 279 void Post(const parser::OmpDefaultClause &); 280 bool Pre(const parser::OmpClause::Shared &x) { 281 ResolveOmpObjectList(x.v, Symbol::Flag::OmpShared); 282 return false; 283 } 284 bool Pre(const parser::OmpClause::Private &x) { 285 ResolveOmpObjectList(x.v, Symbol::Flag::OmpPrivate); 286 return false; 287 } 288 bool Pre(const parser::OmpAllocateClause &x) { 289 const auto &objectList{std::get<parser::OmpObjectList>(x.t)}; 290 ResolveOmpObjectList(objectList, Symbol::Flag::OmpAllocate); 291 return false; 292 } 293 bool Pre(const parser::OmpClause::Firstprivate &x) { 294 ResolveOmpObjectList(x.v, Symbol::Flag::OmpFirstPrivate); 295 return false; 296 } 297 bool Pre(const parser::OmpClause::Lastprivate &x) { 298 ResolveOmpObjectList(x.v, Symbol::Flag::OmpLastPrivate); 299 return false; 300 } 301 bool Pre(const parser::OmpClause::Copyin &x) { 302 ResolveOmpObjectList(x.v, Symbol::Flag::OmpCopyIn); 303 return false; 304 } 305 bool Pre(const parser::OmpLinearClause &x) { 306 std::visit(common::visitors{ 307 [&](const parser::OmpLinearClause::WithoutModifier 308 &linearWithoutModifier) { 309 ResolveOmpNameList( 310 linearWithoutModifier.names, Symbol::Flag::OmpLinear); 311 }, 312 [&](const parser::OmpLinearClause::WithModifier 313 &linearWithModifier) { 314 ResolveOmpNameList( 315 linearWithModifier.names, Symbol::Flag::OmpLinear); 316 }, 317 }, 318 x.u); 319 return false; 320 } 321 bool Pre(const parser::OmpAlignedClause &x) { 322 const auto &alignedNameList{std::get<std::list<parser::Name>>(x.t)}; 323 ResolveOmpNameList(alignedNameList, Symbol::Flag::OmpAligned); 324 return false; 325 } 326 void Post(const parser::Name &); 327 328 const parser::OmpClause *associatedClause{nullptr}; 329 void SetAssociatedClause(const parser::OmpClause &c) { 330 associatedClause = &c; 331 } 332 const parser::OmpClause *GetAssociatedClause() { return associatedClause; } 333 334 private: 335 std::int64_t GetAssociatedLoopLevelFromClauses(const parser::OmpClauseList &); 336 337 static constexpr Symbol::Flags dataSharingAttributeFlags{ 338 Symbol::Flag::OmpShared, Symbol::Flag::OmpPrivate, 339 Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate, 340 Symbol::Flag::OmpReduction, Symbol::Flag::OmpLinear}; 341 342 static constexpr Symbol::Flags privateDataSharingAttributeFlags{ 343 Symbol::Flag::OmpPrivate, Symbol::Flag::OmpFirstPrivate, 344 Symbol::Flag::OmpLastPrivate}; 345 346 static constexpr Symbol::Flags ompFlagsRequireNewSymbol{ 347 Symbol::Flag::OmpPrivate, Symbol::Flag::OmpLinear, 348 Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate, 349 Symbol::Flag::OmpReduction}; 350 351 static constexpr Symbol::Flags ompFlagsRequireMark{ 352 Symbol::Flag::OmpThreadprivate}; 353 354 static constexpr Symbol::Flags dataCopyingAttributeFlags{ 355 Symbol::Flag::OmpCopyIn}; 356 357 std::vector<const parser::Name *> allocateNames_; // on one directive 358 SymbolSet privateDataSharingAttributeObjects_; // on one directive 359 SymbolSet stmtFunctionExprSymbols_; 360 361 void AddAllocateName(const parser::Name *&object) { 362 allocateNames_.push_back(object); 363 } 364 void ClearAllocateNames() { allocateNames_.clear(); } 365 366 void AddPrivateDataSharingAttributeObjects(SymbolRef object) { 367 privateDataSharingAttributeObjects_.insert(object); 368 } 369 void ClearPrivateDataSharingAttributeObjects() { 370 privateDataSharingAttributeObjects_.clear(); 371 } 372 373 // Predetermined DSA rules 374 void PrivatizeAssociatedLoopIndexAndCheckLoopLevel( 375 const parser::OpenMPLoopConstruct &); 376 void ResolveSeqLoopIndexInParallelOrTaskConstruct(const parser::Name &); 377 378 void ResolveOmpObjectList(const parser::OmpObjectList &, Symbol::Flag); 379 void ResolveOmpObject(const parser::OmpObject &, Symbol::Flag); 380 Symbol *ResolveOmp(const parser::Name &, Symbol::Flag, Scope &); 381 Symbol *ResolveOmp(Symbol &, Symbol::Flag, Scope &); 382 Symbol *ResolveOmpCommonBlockName(const parser::Name *); 383 void ResolveOmpNameList(const std::list<parser::Name> &, Symbol::Flag); 384 void ResolveOmpName(const parser::Name &, Symbol::Flag); 385 Symbol *ResolveName(const parser::Name *); 386 Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag); 387 Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag); 388 void CheckMultipleAppearances( 389 const parser::Name &, const Symbol &, Symbol::Flag); 390 391 void CheckDataCopyingClause( 392 const parser::Name &, const Symbol &, Symbol::Flag); 393 394 void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause); 395 void CheckPrivateDSAObject( 396 const parser::Name &, const Symbol &, Symbol::Flag); 397 }; 398 399 template <typename T> 400 bool DirectiveAttributeVisitor<T>::HasDataSharingAttributeObject( 401 const Symbol &object) { 402 auto it{dataSharingAttributeObjects_.find(object)}; 403 return it != dataSharingAttributeObjects_.end(); 404 } 405 406 template <typename T> 407 const parser::Name &DirectiveAttributeVisitor<T>::GetLoopIndex( 408 const parser::DoConstruct &x) { 409 using Bounds = parser::LoopControl::Bounds; 410 return std::get<Bounds>(x.GetLoopControl()->u).name.thing; 411 } 412 413 template <typename T> 414 const parser::DoConstruct *DirectiveAttributeVisitor<T>::GetDoConstructIf( 415 const parser::ExecutionPartConstruct &x) { 416 return parser::Unwrap<parser::DoConstruct>(x); 417 } 418 419 template <typename T> 420 Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity( 421 const parser::Name &name, Symbol::Flag flag, Scope &scope) { 422 if (!name.symbol) { 423 return nullptr; // not resolved by Name Resolution step, do nothing 424 } 425 name.symbol = DeclarePrivateAccessEntity(*name.symbol, flag, scope); 426 return name.symbol; 427 } 428 429 template <typename T> 430 Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity( 431 Symbol &object, Symbol::Flag flag, Scope &scope) { 432 if (object.owner() != currScope()) { 433 auto &symbol{MakeAssocSymbol(object.name(), object, scope)}; 434 symbol.set(flag); 435 return &symbol; 436 } else { 437 object.set(flag); 438 return &object; 439 } 440 } 441 442 bool AccAttributeVisitor::Pre(const parser::OpenACCBlockConstruct &x) { 443 const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)}; 444 const auto &blockDir{std::get<parser::AccBlockDirective>(beginBlockDir.t)}; 445 switch (blockDir.v) { 446 case llvm::acc::Directive::ACCD_data: 447 case llvm::acc::Directive::ACCD_host_data: 448 case llvm::acc::Directive::ACCD_kernels: 449 case llvm::acc::Directive::ACCD_parallel: 450 case llvm::acc::Directive::ACCD_serial: 451 PushContext(blockDir.source, blockDir.v); 452 break; 453 default: 454 break; 455 } 456 ClearDataSharingAttributeObjects(); 457 return true; 458 } 459 460 bool AccAttributeVisitor::Pre(const parser::OpenACCDeclarativeConstruct &x) { 461 if (const auto *declConstruct{ 462 std::get_if<parser::OpenACCStandaloneDeclarativeConstruct>(&x.u)}) { 463 const auto &declDir{ 464 std::get<parser::AccDeclarativeDirective>(declConstruct->t)}; 465 PushContext(declDir.source, llvm::acc::Directive::ACCD_declare); 466 } else if (const auto *routineConstruct{ 467 std::get_if<parser::OpenACCRoutineConstruct>(&x.u)}) { 468 const auto &verbatim{std::get<parser::Verbatim>(routineConstruct->t)}; 469 PushContext(verbatim.source, llvm::acc::Directive::ACCD_routine); 470 } 471 ClearDataSharingAttributeObjects(); 472 return true; 473 } 474 475 static const parser::AccObjectList &GetAccObjectList( 476 const parser::AccClause &clause) { 477 if (const auto *copyClause = 478 std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) { 479 return copyClause->v; 480 } else if (const auto *createClause = 481 std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) { 482 const Fortran::parser::AccObjectListWithModifier &listWithModifier = 483 createClause->v; 484 const Fortran::parser::AccObjectList &accObjectList = 485 std::get<Fortran::parser::AccObjectList>(listWithModifier.t); 486 return accObjectList; 487 } else if (const auto *copyinClause = 488 std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) { 489 const Fortran::parser::AccObjectListWithModifier &listWithModifier = 490 copyinClause->v; 491 const Fortran::parser::AccObjectList &accObjectList = 492 std::get<Fortran::parser::AccObjectList>(listWithModifier.t); 493 return accObjectList; 494 } else if (const auto *copyoutClause = 495 std::get_if<Fortran::parser::AccClause::Copyout>(&clause.u)) { 496 const Fortran::parser::AccObjectListWithModifier &listWithModifier = 497 copyoutClause->v; 498 const Fortran::parser::AccObjectList &accObjectList = 499 std::get<Fortran::parser::AccObjectList>(listWithModifier.t); 500 return accObjectList; 501 } else if (const auto *presentClause = 502 std::get_if<Fortran::parser::AccClause::Present>(&clause.u)) { 503 return presentClause->v; 504 } else if (const auto *deviceptrClause = 505 std::get_if<Fortran::parser::AccClause::Deviceptr>( 506 &clause.u)) { 507 return deviceptrClause->v; 508 } else if (const auto *deviceResidentClause = 509 std::get_if<Fortran::parser::AccClause::DeviceResident>( 510 &clause.u)) { 511 return deviceResidentClause->v; 512 } else if (const auto *linkClause = 513 std::get_if<Fortran::parser::AccClause::Link>(&clause.u)) { 514 return linkClause->v; 515 } else { 516 llvm_unreachable("Clause without object list!"); 517 } 518 } 519 520 void AccAttributeVisitor::Post( 521 const parser::OpenACCStandaloneDeclarativeConstruct &x) { 522 const auto &clauseList = std::get<parser::AccClauseList>(x.t); 523 for (const auto &clause : clauseList.v) { 524 // Restriction - line 2414 525 DoNotAllowAssumedSizedArray(GetAccObjectList(clause)); 526 } 527 } 528 529 bool AccAttributeVisitor::Pre(const parser::OpenACCLoopConstruct &x) { 530 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)}; 531 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)}; 532 const auto &clauseList{std::get<parser::AccClauseList>(beginDir.t)}; 533 if (loopDir.v == llvm::acc::Directive::ACCD_loop) { 534 PushContext(loopDir.source, loopDir.v); 535 } 536 ClearDataSharingAttributeObjects(); 537 SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList)); 538 PrivatizeAssociatedLoopIndex(x); 539 return true; 540 } 541 542 bool AccAttributeVisitor::Pre(const parser::OpenACCStandaloneConstruct &x) { 543 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)}; 544 switch (standaloneDir.v) { 545 case llvm::acc::Directive::ACCD_enter_data: 546 case llvm::acc::Directive::ACCD_exit_data: 547 case llvm::acc::Directive::ACCD_init: 548 case llvm::acc::Directive::ACCD_set: 549 case llvm::acc::Directive::ACCD_shutdown: 550 case llvm::acc::Directive::ACCD_update: 551 PushContext(standaloneDir.source, standaloneDir.v); 552 break; 553 default: 554 break; 555 } 556 ClearDataSharingAttributeObjects(); 557 return true; 558 } 559 560 Symbol *AccAttributeVisitor::ResolveName(const parser::Name &name) { 561 Symbol *prev{currScope().FindSymbol(name.source)}; 562 if (prev != name.symbol) { 563 name.symbol = prev; 564 } 565 return prev; 566 } 567 568 bool AccAttributeVisitor::Pre(const parser::OpenACCRoutineConstruct &x) { 569 const auto &optName{std::get<std::optional<parser::Name>>(x.t)}; 570 if (optName) { 571 if (!ResolveName(*optName)) 572 context_.Say((*optName).source, 573 "No function or subroutine declared for '%s'"_err_en_US, 574 (*optName).source); 575 } 576 return true; 577 } 578 579 bool AccAttributeVisitor::Pre(const parser::AccBindClause &x) { 580 if (const auto *name{std::get_if<parser::Name>(&x.u)}) { 581 if (!ResolveName(*name)) 582 context_.Say(name->source, 583 "No function or subroutine declared for '%s'"_err_en_US, 584 name->source); 585 } 586 return true; 587 } 588 589 bool AccAttributeVisitor::Pre(const parser::OpenACCCombinedConstruct &x) { 590 const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)}; 591 const auto &combinedDir{ 592 std::get<parser::AccCombinedDirective>(beginBlockDir.t)}; 593 switch (combinedDir.v) { 594 case llvm::acc::Directive::ACCD_kernels_loop: 595 case llvm::acc::Directive::ACCD_parallel_loop: 596 case llvm::acc::Directive::ACCD_serial_loop: 597 PushContext(combinedDir.source, combinedDir.v); 598 break; 599 default: 600 break; 601 } 602 ClearDataSharingAttributeObjects(); 603 return true; 604 } 605 606 static bool IsLastNameArray(const parser::Designator &designator) { 607 const auto &name{GetLastName(designator)}; 608 const evaluate::DataRef dataRef{*(name.symbol)}; 609 return std::visit( 610 common::visitors{ 611 [](const evaluate::SymbolRef &ref) { return ref->Rank() > 0; }, 612 [](const evaluate::ArrayRef &aref) { 613 return aref.base().IsSymbol() || 614 aref.base().GetComponent().base().Rank() == 0; 615 }, 616 [](const auto &) { return false; }, 617 }, 618 dataRef.u); 619 } 620 621 void AccAttributeVisitor::AllowOnlyArrayAndSubArray( 622 const parser::AccObjectList &objectList) { 623 for (const auto &accObject : objectList.v) { 624 std::visit( 625 common::visitors{ 626 [&](const parser::Designator &designator) { 627 if (!IsLastNameArray(designator)) 628 context_.Say(designator.source, 629 "Only array element or subarray are allowed in %s directive"_err_en_US, 630 parser::ToUpperCaseLetters( 631 llvm::acc::getOpenACCDirectiveName( 632 GetContext().directive) 633 .str())); 634 }, 635 [&](const auto &name) { 636 context_.Say(name.source, 637 "Only array element or subarray are allowed in %s directive"_err_en_US, 638 parser::ToUpperCaseLetters( 639 llvm::acc::getOpenACCDirectiveName(GetContext().directive) 640 .str())); 641 }, 642 }, 643 accObject.u); 644 } 645 } 646 647 void AccAttributeVisitor::DoNotAllowAssumedSizedArray( 648 const parser::AccObjectList &objectList) { 649 for (const auto &accObject : objectList.v) { 650 std::visit( 651 common::visitors{ 652 [&](const parser::Designator &designator) { 653 const auto &name{GetLastName(designator)}; 654 if (name.symbol && semantics::IsAssumedSizeArray(*name.symbol)) 655 context_.Say(designator.source, 656 "Assumed-size dummy arrays may not appear on the %s " 657 "directive"_err_en_US, 658 parser::ToUpperCaseLetters( 659 llvm::acc::getOpenACCDirectiveName( 660 GetContext().directive) 661 .str())); 662 }, 663 [&](const auto &name) { 664 665 }, 666 }, 667 accObject.u); 668 } 669 } 670 671 bool AccAttributeVisitor::Pre(const parser::OpenACCCacheConstruct &x) { 672 const auto &verbatim{std::get<parser::Verbatim>(x.t)}; 673 PushContext(verbatim.source, llvm::acc::Directive::ACCD_cache); 674 ClearDataSharingAttributeObjects(); 675 676 const auto &objectListWithModifier = 677 std::get<parser::AccObjectListWithModifier>(x.t); 678 const auto &objectList = 679 std::get<Fortran::parser::AccObjectList>(objectListWithModifier.t); 680 681 // 2.10 Cache directive restriction: A var in a cache directive must be a 682 // single array element or a simple subarray. 683 AllowOnlyArrayAndSubArray(objectList); 684 685 return true; 686 } 687 688 std::int64_t AccAttributeVisitor::GetAssociatedLoopLevelFromClauses( 689 const parser::AccClauseList &x) { 690 std::int64_t collapseLevel{0}; 691 for (const auto &clause : x.v) { 692 if (const auto *collapseClause{ 693 std::get_if<parser::AccClause::Collapse>(&clause.u)}) { 694 if (const auto v{EvaluateInt64(context_, collapseClause->v)}) { 695 collapseLevel = *v; 696 } 697 } 698 } 699 700 if (collapseLevel) { 701 return collapseLevel; 702 } 703 return 1; // default is outermost loop 704 } 705 706 void AccAttributeVisitor::PrivatizeAssociatedLoopIndex( 707 const parser::OpenACCLoopConstruct &x) { 708 std::int64_t level{GetContext().associatedLoopLevel}; 709 if (level <= 0) { // collpase value was negative or 0 710 return; 711 } 712 Symbol::Flag ivDSA{Symbol::Flag::AccPrivate}; 713 714 const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)}; 715 for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) { 716 // go through all the nested do-loops and resolve index variables 717 const parser::Name &iv{GetLoopIndex(*loop)}; 718 if (auto *symbol{ResolveAcc(iv, ivDSA, currScope())}) { 719 symbol->set(Symbol::Flag::AccPreDetermined); 720 iv.symbol = symbol; // adjust the symbol within region 721 AddToContextObjectWithDSA(*symbol, ivDSA); 722 } 723 724 const auto &block{std::get<parser::Block>(loop->t)}; 725 const auto it{block.begin()}; 726 loop = it != block.end() ? GetDoConstructIf(*it) : nullptr; 727 } 728 CHECK(level == 0); 729 } 730 731 void AccAttributeVisitor::Post(const parser::AccDefaultClause &x) { 732 if (!dirContext_.empty()) { 733 switch (x.v) { 734 case llvm::acc::DefaultValue::ACC_Default_present: 735 SetContextDefaultDSA(Symbol::Flag::AccPresent); 736 break; 737 case llvm::acc::DefaultValue::ACC_Default_none: 738 SetContextDefaultDSA(Symbol::Flag::AccNone); 739 break; 740 } 741 } 742 } 743 744 // For OpenACC constructs, check all the data-refs within the constructs 745 // and adjust the symbol for each Name if necessary 746 void AccAttributeVisitor::Post(const parser::Name &name) { 747 auto *symbol{name.symbol}; 748 if (symbol && !dirContext_.empty() && GetContext().withinConstruct) { 749 if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() && 750 !IsObjectWithDSA(*symbol)) { 751 if (Symbol * found{currScope().FindSymbol(name.source)}) { 752 if (symbol != found) { 753 name.symbol = found; // adjust the symbol within region 754 } else if (GetContext().defaultDSA == Symbol::Flag::AccNone) { 755 // 2.5.14. 756 context_.Say(name.source, 757 "The DEFAULT(NONE) clause requires that '%s' must be listed in " 758 "a data-mapping clause"_err_en_US, 759 symbol->name()); 760 } 761 } 762 } 763 } // within OpenACC construct 764 } 765 766 Symbol *AccAttributeVisitor::ResolveAccCommonBlockName( 767 const parser::Name *name) { 768 if (!name) { 769 return nullptr; 770 } else if (auto *prev{ 771 GetContext().scope.parent().FindCommonBlock(name->source)}) { 772 name->symbol = prev; 773 return prev; 774 } else { 775 return nullptr; 776 } 777 } 778 779 void AccAttributeVisitor::ResolveAccObjectList( 780 const parser::AccObjectList &accObjectList, Symbol::Flag accFlag) { 781 for (const auto &accObject : accObjectList.v) { 782 ResolveAccObject(accObject, accFlag); 783 } 784 } 785 786 void AccAttributeVisitor::ResolveAccObject( 787 const parser::AccObject &accObject, Symbol::Flag accFlag) { 788 std::visit( 789 common::visitors{ 790 [&](const parser::Designator &designator) { 791 if (const auto *name{GetDesignatorNameIfDataRef(designator)}) { 792 if (auto *symbol{ResolveAcc(*name, accFlag, currScope())}) { 793 AddToContextObjectWithDSA(*symbol, accFlag); 794 if (dataSharingAttributeFlags.test(accFlag)) { 795 CheckMultipleAppearances(*name, *symbol, accFlag); 796 } 797 } 798 } else { 799 // Array sections to be changed to substrings as needed 800 if (AnalyzeExpr(context_, designator)) { 801 if (std::holds_alternative<parser::Substring>(designator.u)) { 802 context_.Say(designator.source, 803 "Substrings are not allowed on OpenACC " 804 "directives or clauses"_err_en_US); 805 } 806 } 807 // other checks, more TBD 808 } 809 }, 810 [&](const parser::Name &name) { // common block 811 if (auto *symbol{ResolveAccCommonBlockName(&name)}) { 812 CheckMultipleAppearances( 813 name, *symbol, Symbol::Flag::AccCommonBlock); 814 for (auto &object : symbol->get<CommonBlockDetails>().objects()) { 815 if (auto *resolvedObject{ 816 ResolveAcc(*object, accFlag, currScope())}) { 817 AddToContextObjectWithDSA(*resolvedObject, accFlag); 818 } 819 } 820 } else { 821 context_.Say(name.source, 822 "COMMON block must be declared in the same scoping unit " 823 "in which the OpenACC directive or clause appears"_err_en_US); 824 } 825 }, 826 }, 827 accObject.u); 828 } 829 830 Symbol *AccAttributeVisitor::ResolveAcc( 831 const parser::Name &name, Symbol::Flag accFlag, Scope &scope) { 832 if (accFlagsRequireNewSymbol.test(accFlag)) { 833 return DeclarePrivateAccessEntity(name, accFlag, scope); 834 } else { 835 return DeclareOrMarkOtherAccessEntity(name, accFlag); 836 } 837 } 838 839 Symbol *AccAttributeVisitor::ResolveAcc( 840 Symbol &symbol, Symbol::Flag accFlag, Scope &scope) { 841 if (accFlagsRequireNewSymbol.test(accFlag)) { 842 return DeclarePrivateAccessEntity(symbol, accFlag, scope); 843 } else { 844 return DeclareOrMarkOtherAccessEntity(symbol, accFlag); 845 } 846 } 847 848 Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity( 849 const parser::Name &name, Symbol::Flag accFlag) { 850 Symbol *prev{currScope().FindSymbol(name.source)}; 851 if (!name.symbol || !prev) { 852 return nullptr; 853 } else if (prev != name.symbol) { 854 name.symbol = prev; 855 } 856 return DeclareOrMarkOtherAccessEntity(*prev, accFlag); 857 } 858 859 Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity( 860 Symbol &object, Symbol::Flag accFlag) { 861 if (accFlagsRequireMark.test(accFlag)) { 862 object.set(accFlag); 863 } 864 return &object; 865 } 866 867 static bool WithMultipleAppearancesAccException( 868 const Symbol &symbol, Symbol::Flag flag) { 869 return false; // Place holder 870 } 871 872 void AccAttributeVisitor::CheckMultipleAppearances( 873 const parser::Name &name, const Symbol &symbol, Symbol::Flag accFlag) { 874 const auto *target{&symbol}; 875 if (accFlagsRequireNewSymbol.test(accFlag)) { 876 if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) { 877 target = &details->symbol(); 878 } 879 } 880 if (HasDataSharingAttributeObject(*target) && 881 !WithMultipleAppearancesAccException(symbol, accFlag)) { 882 context_.Say(name.source, 883 "'%s' appears in more than one data-sharing clause " 884 "on the same OpenACC directive"_err_en_US, 885 name.ToString()); 886 } else { 887 AddDataSharingAttributeObject(*target); 888 } 889 } 890 891 bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) { 892 const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)}; 893 const auto &beginDir{std::get<parser::OmpBlockDirective>(beginBlockDir.t)}; 894 switch (beginDir.v) { 895 case llvm::omp::Directive::OMPD_master: 896 case llvm::omp::Directive::OMPD_ordered: 897 case llvm::omp::Directive::OMPD_parallel: 898 case llvm::omp::Directive::OMPD_single: 899 case llvm::omp::Directive::OMPD_target: 900 case llvm::omp::Directive::OMPD_target_data: 901 case llvm::omp::Directive::OMPD_task: 902 case llvm::omp::Directive::OMPD_teams: 903 case llvm::omp::Directive::OMPD_workshare: 904 case llvm::omp::Directive::OMPD_parallel_workshare: 905 case llvm::omp::Directive::OMPD_target_teams: 906 case llvm::omp::Directive::OMPD_target_parallel: 907 PushContext(beginDir.source, beginDir.v); 908 break; 909 default: 910 // TODO others 911 break; 912 } 913 ClearDataSharingAttributeObjects(); 914 ClearPrivateDataSharingAttributeObjects(); 915 ClearAllocateNames(); 916 return true; 917 } 918 919 void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) { 920 const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)}; 921 const auto &beginDir{std::get<parser::OmpBlockDirective>(beginBlockDir.t)}; 922 switch (beginDir.v) { 923 case llvm::omp::Directive::OMPD_parallel: 924 case llvm::omp::Directive::OMPD_single: 925 case llvm::omp::Directive::OMPD_target: 926 case llvm::omp::Directive::OMPD_task: 927 case llvm::omp::Directive::OMPD_teams: 928 case llvm::omp::Directive::OMPD_parallel_workshare: 929 case llvm::omp::Directive::OMPD_target_teams: 930 case llvm::omp::Directive::OMPD_target_parallel: { 931 bool hasPrivate; 932 for (const auto *allocName : allocateNames_) { 933 hasPrivate = false; 934 for (auto privateObj : privateDataSharingAttributeObjects_) { 935 const Symbol &symbolPrivate{*privateObj}; 936 if (allocName->source == symbolPrivate.name()) { 937 hasPrivate = true; 938 break; 939 } 940 } 941 if (!hasPrivate) { 942 context_.Say(allocName->source, 943 "The ALLOCATE clause requires that '%s' must be listed in a " 944 "private " 945 "data-sharing attribute clause on the same directive"_err_en_US, 946 allocName->ToString()); 947 } 948 } 949 break; 950 } 951 default: 952 break; 953 } 954 PopContext(); 955 } 956 957 bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) { 958 const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)}; 959 const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)}; 960 const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)}; 961 switch (beginDir.v) { 962 case llvm::omp::Directive::OMPD_distribute: 963 case llvm::omp::Directive::OMPD_distribute_parallel_do: 964 case llvm::omp::Directive::OMPD_distribute_parallel_do_simd: 965 case llvm::omp::Directive::OMPD_distribute_simd: 966 case llvm::omp::Directive::OMPD_do: 967 case llvm::omp::Directive::OMPD_do_simd: 968 case llvm::omp::Directive::OMPD_parallel_do: 969 case llvm::omp::Directive::OMPD_parallel_do_simd: 970 case llvm::omp::Directive::OMPD_simd: 971 case llvm::omp::Directive::OMPD_target_parallel_do: 972 case llvm::omp::Directive::OMPD_target_parallel_do_simd: 973 case llvm::omp::Directive::OMPD_target_teams_distribute: 974 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do: 975 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: 976 case llvm::omp::Directive::OMPD_target_teams_distribute_simd: 977 case llvm::omp::Directive::OMPD_target_simd: 978 case llvm::omp::Directive::OMPD_taskloop: 979 case llvm::omp::Directive::OMPD_taskloop_simd: 980 case llvm::omp::Directive::OMPD_teams_distribute: 981 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do: 982 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd: 983 case llvm::omp::Directive::OMPD_teams_distribute_simd: 984 PushContext(beginDir.source, beginDir.v); 985 break; 986 default: 987 break; 988 } 989 ClearDataSharingAttributeObjects(); 990 SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList)); 991 PrivatizeAssociatedLoopIndexAndCheckLoopLevel(x); 992 return true; 993 } 994 995 void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct( 996 const parser::Name &iv) { 997 auto targetIt{dirContext_.rbegin()}; 998 for (;; ++targetIt) { 999 if (targetIt == dirContext_.rend()) { 1000 return; 1001 } 1002 if (llvm::omp::parallelSet.test(targetIt->directive) || 1003 llvm::omp::taskGeneratingSet.test(targetIt->directive)) { 1004 break; 1005 } 1006 } 1007 if (auto *symbol{ResolveOmp(iv, Symbol::Flag::OmpPrivate, targetIt->scope)}) { 1008 targetIt++; 1009 symbol->set(Symbol::Flag::OmpPreDetermined); 1010 iv.symbol = symbol; // adjust the symbol within region 1011 for (auto it{dirContext_.rbegin()}; it != targetIt; ++it) { 1012 AddToContextObjectWithDSA(*symbol, Symbol::Flag::OmpPrivate, *it); 1013 } 1014 } 1015 } 1016 1017 // [OMP-4.5]2.15.1.1 Data-sharing Attribute Rules - Predetermined 1018 // - A loop iteration variable for a sequential loop in a parallel 1019 // or task generating construct is private in the innermost such 1020 // construct that encloses the loop 1021 // Loop iteration variables are not well defined for DO WHILE loop. 1022 // Use of DO CONCURRENT inside OpenMP construct is unspecified behavior 1023 // till OpenMP-5.0 standard. 1024 // In above both cases we skip the privatization of iteration variables. 1025 bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) { 1026 // TODO:[OpenMP 5.1] DO CONCURRENT indices are private 1027 if (x.IsDoNormal()) { 1028 if (!dirContext_.empty() && GetContext().withinConstruct) { 1029 if (const auto &iv{GetLoopIndex(x)}; iv.symbol) { 1030 if (!iv.symbol->test(Symbol::Flag::OmpPreDetermined)) { 1031 ResolveSeqLoopIndexInParallelOrTaskConstruct(iv); 1032 } else { 1033 // TODO: conflict checks with explicitly determined DSA 1034 } 1035 } 1036 } 1037 } 1038 return true; 1039 } 1040 1041 std::int64_t OmpAttributeVisitor::GetAssociatedLoopLevelFromClauses( 1042 const parser::OmpClauseList &x) { 1043 std::int64_t orderedLevel{0}; 1044 std::int64_t collapseLevel{0}; 1045 1046 const parser::OmpClause *ordClause{nullptr}; 1047 const parser::OmpClause *collClause{nullptr}; 1048 1049 for (const auto &clause : x.v) { 1050 if (const auto *orderedClause{ 1051 std::get_if<parser::OmpClause::Ordered>(&clause.u)}) { 1052 if (const auto v{EvaluateInt64(context_, orderedClause->v)}) { 1053 orderedLevel = *v; 1054 } 1055 ordClause = &clause; 1056 } 1057 if (const auto *collapseClause{ 1058 std::get_if<parser::OmpClause::Collapse>(&clause.u)}) { 1059 if (const auto v{EvaluateInt64(context_, collapseClause->v)}) { 1060 collapseLevel = *v; 1061 } 1062 collClause = &clause; 1063 } 1064 } 1065 1066 if (orderedLevel && (!collapseLevel || orderedLevel >= collapseLevel)) { 1067 SetAssociatedClause(*ordClause); 1068 return orderedLevel; 1069 } else if (!orderedLevel && collapseLevel) { 1070 SetAssociatedClause(*collClause); 1071 return collapseLevel; 1072 } // orderedLevel < collapseLevel is an error handled in structural checks 1073 return 1; // default is outermost loop 1074 } 1075 1076 // 2.15.1.1 Data-sharing Attribute Rules - Predetermined 1077 // - The loop iteration variable(s) in the associated do-loop(s) of a do, 1078 // parallel do, taskloop, or distribute construct is (are) private. 1079 // - The loop iteration variable in the associated do-loop of a simd construct 1080 // with just one associated do-loop is linear with a linear-step that is the 1081 // increment of the associated do-loop. 1082 // - The loop iteration variables in the associated do-loops of a simd 1083 // construct with multiple associated do-loops are lastprivate. 1084 void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel( 1085 const parser::OpenMPLoopConstruct &x) { 1086 std::int64_t level{GetContext().associatedLoopLevel}; 1087 if (level <= 0) { 1088 return; 1089 } 1090 Symbol::Flag ivDSA; 1091 if (!llvm::omp::simdSet.test(GetContext().directive)) { 1092 ivDSA = Symbol::Flag::OmpPrivate; 1093 } else if (level == 1) { 1094 ivDSA = Symbol::Flag::OmpLinear; 1095 } else { 1096 ivDSA = Symbol::Flag::OmpLastPrivate; 1097 } 1098 1099 const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)}; 1100 for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) { 1101 // go through all the nested do-loops and resolve index variables 1102 const parser::Name &iv{GetLoopIndex(*loop)}; 1103 if (auto *symbol{ResolveOmp(iv, ivDSA, currScope())}) { 1104 symbol->set(Symbol::Flag::OmpPreDetermined); 1105 iv.symbol = symbol; // adjust the symbol within region 1106 AddToContextObjectWithDSA(*symbol, ivDSA); 1107 } 1108 1109 const auto &block{std::get<parser::Block>(loop->t)}; 1110 const auto it{block.begin()}; 1111 loop = it != block.end() ? GetDoConstructIf(*it) : nullptr; 1112 } 1113 CheckAssocLoopLevel(level, GetAssociatedClause()); 1114 } 1115 void OmpAttributeVisitor::CheckAssocLoopLevel( 1116 std::int64_t level, const parser::OmpClause *clause) { 1117 if (clause && level != 0) { 1118 context_.Say(clause->source, 1119 "The value of the parameter in the COLLAPSE or ORDERED clause must" 1120 " not be larger than the number of nested loops" 1121 " following the construct."_err_en_US); 1122 } 1123 } 1124 1125 bool OmpAttributeVisitor::Pre(const parser::OpenMPSectionsConstruct &x) { 1126 const auto &beginSectionsDir{ 1127 std::get<parser::OmpBeginSectionsDirective>(x.t)}; 1128 const auto &beginDir{ 1129 std::get<parser::OmpSectionsDirective>(beginSectionsDir.t)}; 1130 switch (beginDir.v) { 1131 case llvm::omp::Directive::OMPD_parallel_sections: 1132 case llvm::omp::Directive::OMPD_sections: 1133 PushContext(beginDir.source, beginDir.v); 1134 break; 1135 default: 1136 break; 1137 } 1138 ClearDataSharingAttributeObjects(); 1139 return true; 1140 } 1141 1142 bool OmpAttributeVisitor::Pre(const parser::OpenMPThreadprivate &x) { 1143 PushContext(x.source, llvm::omp::Directive::OMPD_threadprivate); 1144 const auto &list{std::get<parser::OmpObjectList>(x.t)}; 1145 ResolveOmpObjectList(list, Symbol::Flag::OmpThreadprivate); 1146 return true; 1147 } 1148 1149 void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) { 1150 if (!dirContext_.empty()) { 1151 switch (x.v) { 1152 case parser::OmpDefaultClause::Type::Private: 1153 SetContextDefaultDSA(Symbol::Flag::OmpPrivate); 1154 break; 1155 case parser::OmpDefaultClause::Type::Firstprivate: 1156 SetContextDefaultDSA(Symbol::Flag::OmpFirstPrivate); 1157 break; 1158 case parser::OmpDefaultClause::Type::Shared: 1159 SetContextDefaultDSA(Symbol::Flag::OmpShared); 1160 break; 1161 case parser::OmpDefaultClause::Type::None: 1162 SetContextDefaultDSA(Symbol::Flag::OmpNone); 1163 break; 1164 } 1165 } 1166 } 1167 1168 // For OpenMP constructs, check all the data-refs within the constructs 1169 // and adjust the symbol for each Name if necessary 1170 void OmpAttributeVisitor::Post(const parser::Name &name) { 1171 auto *symbol{name.symbol}; 1172 if (symbol && !dirContext_.empty() && GetContext().withinConstruct) { 1173 if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() && 1174 !IsObjectWithDSA(*symbol)) { 1175 // TODO: create a separate function to go through the rules for 1176 // predetermined, explicitly determined, and implicitly 1177 // determined data-sharing attributes (2.15.1.1). 1178 if (Symbol * found{currScope().FindSymbol(name.source)}) { 1179 if (symbol != found) { 1180 name.symbol = found; // adjust the symbol within region 1181 } else if (GetContext().defaultDSA == Symbol::Flag::OmpNone) { 1182 context_.Say(name.source, 1183 "The DEFAULT(NONE) clause requires that '%s' must be listed in " 1184 "a data-sharing attribute clause"_err_en_US, 1185 symbol->name()); 1186 } 1187 } 1188 } 1189 } // within OpenMP construct 1190 } 1191 1192 Symbol *OmpAttributeVisitor::ResolveName(const parser::Name *name) { 1193 if (auto *resolvedSymbol{ 1194 name ? GetContext().scope.FindSymbol(name->source) : nullptr}) { 1195 name->symbol = resolvedSymbol; 1196 return resolvedSymbol; 1197 } else { 1198 return nullptr; 1199 } 1200 } 1201 1202 void OmpAttributeVisitor::ResolveOmpName( 1203 const parser::Name &name, Symbol::Flag ompFlag) { 1204 if (ResolveName(&name)) { 1205 if (auto *resolvedSymbol{ResolveOmp(name, ompFlag, currScope())}) { 1206 if (dataSharingAttributeFlags.test(ompFlag)) { 1207 AddToContextObjectWithDSA(*resolvedSymbol, ompFlag); 1208 } 1209 } 1210 } 1211 } 1212 1213 void OmpAttributeVisitor::ResolveOmpNameList( 1214 const std::list<parser::Name> &nameList, Symbol::Flag ompFlag) { 1215 for (const auto &name : nameList) { 1216 ResolveOmpName(name, ompFlag); 1217 } 1218 } 1219 1220 Symbol *OmpAttributeVisitor::ResolveOmpCommonBlockName( 1221 const parser::Name *name) { 1222 if (auto *prev{name 1223 ? GetContext().scope.parent().FindCommonBlock(name->source) 1224 : nullptr}) { 1225 name->symbol = prev; 1226 return prev; 1227 } 1228 // Check if the Common Block is declared in the current scope 1229 if (auto *commonBlockSymbol{ 1230 name ? GetContext().scope.FindCommonBlock(name->source) : nullptr}) { 1231 name->symbol = commonBlockSymbol; 1232 return commonBlockSymbol; 1233 } 1234 return nullptr; 1235 } 1236 1237 void OmpAttributeVisitor::ResolveOmpObjectList( 1238 const parser::OmpObjectList &ompObjectList, Symbol::Flag ompFlag) { 1239 for (const auto &ompObject : ompObjectList.v) { 1240 ResolveOmpObject(ompObject, ompFlag); 1241 } 1242 } 1243 1244 void OmpAttributeVisitor::ResolveOmpObject( 1245 const parser::OmpObject &ompObject, Symbol::Flag ompFlag) { 1246 std::visit( 1247 common::visitors{ 1248 [&](const parser::Designator &designator) { 1249 if (const auto *name{GetDesignatorNameIfDataRef(designator)}) { 1250 if (auto *symbol{ResolveOmp(*name, ompFlag, currScope())}) { 1251 if (dataCopyingAttributeFlags.test(ompFlag)) { 1252 CheckDataCopyingClause(*name, *symbol, ompFlag); 1253 } else { 1254 AddToContextObjectWithDSA(*symbol, ompFlag); 1255 if (dataSharingAttributeFlags.test(ompFlag)) { 1256 CheckMultipleAppearances(*name, *symbol, ompFlag); 1257 } 1258 if (privateDataSharingAttributeFlags.test(ompFlag)) { 1259 CheckPrivateDSAObject(*name, *symbol, ompFlag); 1260 } 1261 1262 if (ompFlag == Symbol::Flag::OmpAllocate) { 1263 AddAllocateName(name); 1264 } 1265 } 1266 } 1267 } else { 1268 // Array sections to be changed to substrings as needed 1269 if (AnalyzeExpr(context_, designator)) { 1270 if (std::holds_alternative<parser::Substring>(designator.u)) { 1271 context_.Say(designator.source, 1272 "Substrings are not allowed on OpenMP " 1273 "directives or clauses"_err_en_US); 1274 } 1275 } 1276 // other checks, more TBD 1277 } 1278 }, 1279 [&](const parser::Name &name) { // common block 1280 if (auto *symbol{ResolveOmpCommonBlockName(&name)}) { 1281 if (!dataCopyingAttributeFlags.test(ompFlag)) { 1282 CheckMultipleAppearances( 1283 name, *symbol, Symbol::Flag::OmpCommonBlock); 1284 } 1285 // 2.15.3 When a named common block appears in a list, it has the 1286 // same meaning as if every explicit member of the common block 1287 // appeared in the list 1288 for (auto &object : symbol->get<CommonBlockDetails>().objects()) { 1289 if (auto *resolvedObject{ 1290 ResolveOmp(*object, ompFlag, currScope())}) { 1291 if (dataCopyingAttributeFlags.test(ompFlag)) { 1292 CheckDataCopyingClause(name, *resolvedObject, ompFlag); 1293 } else { 1294 AddToContextObjectWithDSA(*resolvedObject, ompFlag); 1295 } 1296 } 1297 } 1298 } else { 1299 context_.Say(name.source, // 2.15.3 1300 "COMMON block must be declared in the same scoping unit " 1301 "in which the OpenMP directive or clause appears"_err_en_US); 1302 } 1303 }, 1304 }, 1305 ompObject.u); 1306 } 1307 1308 Symbol *OmpAttributeVisitor::ResolveOmp( 1309 const parser::Name &name, Symbol::Flag ompFlag, Scope &scope) { 1310 if (ompFlagsRequireNewSymbol.test(ompFlag)) { 1311 return DeclarePrivateAccessEntity(name, ompFlag, scope); 1312 } else { 1313 return DeclareOrMarkOtherAccessEntity(name, ompFlag); 1314 } 1315 } 1316 1317 Symbol *OmpAttributeVisitor::ResolveOmp( 1318 Symbol &symbol, Symbol::Flag ompFlag, Scope &scope) { 1319 if (ompFlagsRequireNewSymbol.test(ompFlag)) { 1320 return DeclarePrivateAccessEntity(symbol, ompFlag, scope); 1321 } else { 1322 return DeclareOrMarkOtherAccessEntity(symbol, ompFlag); 1323 } 1324 } 1325 1326 Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity( 1327 const parser::Name &name, Symbol::Flag ompFlag) { 1328 Symbol *prev{currScope().FindSymbol(name.source)}; 1329 if (!name.symbol || !prev) { 1330 return nullptr; 1331 } else if (prev != name.symbol) { 1332 name.symbol = prev; 1333 } 1334 return DeclareOrMarkOtherAccessEntity(*prev, ompFlag); 1335 } 1336 1337 Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity( 1338 Symbol &object, Symbol::Flag ompFlag) { 1339 if (ompFlagsRequireMark.test(ompFlag)) { 1340 object.set(ompFlag); 1341 } 1342 return &object; 1343 } 1344 1345 static bool WithMultipleAppearancesOmpException( 1346 const Symbol &symbol, Symbol::Flag flag) { 1347 return (flag == Symbol::Flag::OmpFirstPrivate && 1348 symbol.test(Symbol::Flag::OmpLastPrivate)) || 1349 (flag == Symbol::Flag::OmpLastPrivate && 1350 symbol.test(Symbol::Flag::OmpFirstPrivate)); 1351 } 1352 1353 void OmpAttributeVisitor::CheckMultipleAppearances( 1354 const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) { 1355 const auto *target{&symbol}; 1356 if (ompFlagsRequireNewSymbol.test(ompFlag)) { 1357 if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) { 1358 target = &details->symbol(); 1359 } 1360 } 1361 if (HasDataSharingAttributeObject(*target) && 1362 !WithMultipleAppearancesOmpException(symbol, ompFlag)) { 1363 context_.Say(name.source, 1364 "'%s' appears in more than one data-sharing clause " 1365 "on the same OpenMP directive"_err_en_US, 1366 name.ToString()); 1367 } else { 1368 AddDataSharingAttributeObject(*target); 1369 if (privateDataSharingAttributeFlags.test(ompFlag)) { 1370 AddPrivateDataSharingAttributeObjects(*target); 1371 } 1372 } 1373 } 1374 1375 void ResolveAccParts( 1376 SemanticsContext &context, const parser::ProgramUnit &node) { 1377 if (context.IsEnabled(common::LanguageFeature::OpenACC)) { 1378 AccAttributeVisitor{context}.Walk(node); 1379 } 1380 } 1381 1382 void ResolveOmpParts( 1383 SemanticsContext &context, const parser::ProgramUnit &node) { 1384 if (context.IsEnabled(common::LanguageFeature::OpenMP)) { 1385 OmpAttributeVisitor{context}.Walk(node); 1386 if (!context.AnyFatalError()) { 1387 // The data-sharing attribute of the loop iteration variable for a 1388 // sequential loop (2.15.1.1) can only be determined when visiting 1389 // the corresponding DoConstruct, a second walk is to adjust the 1390 // symbols for all the data-refs of that loop iteration variable 1391 // prior to the DoConstruct. 1392 OmpAttributeVisitor{context}.Walk(node); 1393 } 1394 } 1395 } 1396 1397 void OmpAttributeVisitor::CheckDataCopyingClause( 1398 const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) { 1399 const auto *checkSymbol{&symbol}; 1400 if (ompFlag == Symbol::Flag::OmpCopyIn) { 1401 if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) 1402 checkSymbol = &details->symbol(); 1403 1404 // List of items/objects that can appear in a 'copyin' clause must be 1405 // 'threadprivate' 1406 if (!checkSymbol->test(Symbol::Flag::OmpThreadprivate)) 1407 context_.Say(name.source, 1408 "Non-THREADPRIVATE object '%s' in COPYIN clause"_err_en_US, 1409 checkSymbol->name()); 1410 } 1411 } 1412 1413 void OmpAttributeVisitor::CheckPrivateDSAObject( 1414 const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) { 1415 const auto &ultimateSymbol{symbol.GetUltimate()}; 1416 llvm::StringRef clauseName{"PRIVATE"}; 1417 if (ompFlag == Symbol::Flag::OmpFirstPrivate) 1418 clauseName = "FIRSTPRIVATE"; 1419 else if (ompFlag == Symbol::Flag::OmpLastPrivate) 1420 clauseName = "LASTPRIVATE"; 1421 1422 if (ultimateSymbol.test(Symbol::Flag::InNamelist)) { 1423 context_.Say(name.source, 1424 "Variable '%s' in NAMELIST cannot be in a %s clause"_err_en_US, 1425 name.ToString(), clauseName.str()); 1426 } 1427 1428 if (stmtFunctionExprSymbols_.find(ultimateSymbol) != 1429 stmtFunctionExprSymbols_.end()) { 1430 context_.Say(name.source, 1431 "Variable '%s' in STATEMENT FUNCTION expression cannot be in a " 1432 "%s clause"_err_en_US, 1433 name.ToString(), clauseName.str()); 1434 } 1435 } 1436 1437 } // namespace Fortran::semantics 1438