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::SpecificationPart &x) { 118 Walk(std::get<std::list<parser::OpenACCDeclarativeConstruct>>(x.t)); 119 return false; 120 } 121 122 bool Pre(const parser::OpenACCBlockConstruct &); 123 void Post(const parser::OpenACCBlockConstruct &) { PopContext(); } 124 bool Pre(const parser::OpenACCCombinedConstruct &); 125 void Post(const parser::OpenACCCombinedConstruct &) { PopContext(); } 126 127 void Post(const parser::AccBeginBlockDirective &) { 128 GetContext().withinConstruct = true; 129 } 130 131 bool Pre(const parser::OpenACCLoopConstruct &); 132 void Post(const parser::OpenACCLoopConstruct &) { PopContext(); } 133 void Post(const parser::AccLoopDirective &) { 134 GetContext().withinConstruct = true; 135 } 136 137 bool Pre(const parser::OpenACCStandaloneConstruct &); 138 void Post(const parser::OpenACCStandaloneConstruct &) { PopContext(); } 139 void Post(const parser::AccStandaloneDirective &) { 140 GetContext().withinConstruct = true; 141 } 142 143 void Post(const parser::AccDefaultClause &); 144 145 bool Pre(const parser::AccClause::Copy &x) { 146 ResolveAccObjectList(x.v, Symbol::Flag::AccCopyIn); 147 ResolveAccObjectList(x.v, Symbol::Flag::AccCopyOut); 148 return false; 149 } 150 151 bool Pre(const parser::AccClause::Create &x) { 152 const auto &objectList{std::get<parser::AccObjectList>(x.v.t)}; 153 ResolveAccObjectList(objectList, Symbol::Flag::AccCreate); 154 return false; 155 } 156 157 bool Pre(const parser::AccClause::Copyin &x) { 158 const auto &objectList{std::get<parser::AccObjectList>(x.v.t)}; 159 ResolveAccObjectList(objectList, Symbol::Flag::AccCopyIn); 160 return false; 161 } 162 163 bool Pre(const parser::AccClause::Copyout &x) { 164 const auto &objectList{std::get<parser::AccObjectList>(x.v.t)}; 165 ResolveAccObjectList(objectList, Symbol::Flag::AccCopyOut); 166 return false; 167 } 168 169 bool Pre(const parser::AccClause::Present &x) { 170 ResolveAccObjectList(x.v, Symbol::Flag::AccPresent); 171 return false; 172 } 173 bool Pre(const parser::AccClause::Private &x) { 174 ResolveAccObjectList(x.v, Symbol::Flag::AccPrivate); 175 return false; 176 } 177 bool Pre(const parser::AccClause::Firstprivate &x) { 178 ResolveAccObjectList(x.v, Symbol::Flag::AccFirstPrivate); 179 return false; 180 } 181 182 void Post(const parser::Name &); 183 184 private: 185 std::int64_t GetAssociatedLoopLevelFromClauses(const parser::AccClauseList &); 186 187 static constexpr Symbol::Flags dataSharingAttributeFlags{ 188 Symbol::Flag::AccShared, Symbol::Flag::AccPrivate, 189 Symbol::Flag::AccPresent, Symbol::Flag::AccFirstPrivate, 190 Symbol::Flag::AccReduction}; 191 192 static constexpr Symbol::Flags dataMappingAttributeFlags{ 193 Symbol::Flag::AccCreate, Symbol::Flag::AccCopyIn, 194 Symbol::Flag::AccCopyOut, Symbol::Flag::AccDelete}; 195 196 static constexpr Symbol::Flags accFlagsRequireNewSymbol{ 197 Symbol::Flag::AccPrivate, Symbol::Flag::AccFirstPrivate, 198 Symbol::Flag::AccReduction}; 199 200 static constexpr Symbol::Flags accFlagsRequireMark{}; 201 202 void PrivatizeAssociatedLoopIndex(const parser::OpenACCLoopConstruct &); 203 void ResolveAccObjectList(const parser::AccObjectList &, Symbol::Flag); 204 void ResolveAccObject(const parser::AccObject &, Symbol::Flag); 205 Symbol *ResolveAcc(const parser::Name &, Symbol::Flag, Scope &); 206 Symbol *ResolveAcc(Symbol &, Symbol::Flag, Scope &); 207 Symbol *ResolveAccCommonBlockName(const parser::Name *); 208 Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag); 209 Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag); 210 void CheckMultipleAppearances( 211 const parser::Name &, const Symbol &, Symbol::Flag); 212 }; 213 214 // Data-sharing and Data-mapping attributes for data-refs in OpenMP construct 215 class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> { 216 public: 217 explicit OmpAttributeVisitor(SemanticsContext &context) 218 : DirectiveAttributeVisitor(context) {} 219 220 template <typename A> void Walk(const A &x) { parser::Walk(x, *this); } 221 template <typename A> bool Pre(const A &) { return true; } 222 template <typename A> void Post(const A &) {} 223 224 bool Pre(const parser::SpecificationPart &x) { 225 Walk(std::get<std::list<parser::OpenMPDeclarativeConstruct>>(x.t)); 226 return true; 227 } 228 229 bool Pre(const parser::OpenMPBlockConstruct &); 230 void Post(const parser::OpenMPBlockConstruct &); 231 232 void Post(const parser::OmpBeginBlockDirective &) { 233 GetContext().withinConstruct = true; 234 } 235 236 bool Pre(const parser::OpenMPLoopConstruct &); 237 void Post(const parser::OpenMPLoopConstruct &) { PopContext(); } 238 void Post(const parser::OmpBeginLoopDirective &) { 239 GetContext().withinConstruct = true; 240 } 241 bool Pre(const parser::DoConstruct &); 242 243 bool Pre(const parser::OpenMPSectionsConstruct &); 244 void Post(const parser::OpenMPSectionsConstruct &) { PopContext(); } 245 246 bool Pre(const parser::OpenMPDeclareSimdConstruct &x) { 247 PushContext(x.source, llvm::omp::Directive::OMPD_declare_simd); 248 const auto &name{std::get<std::optional<parser::Name>>(x.t)}; 249 if (name) { 250 ResolveOmpName(*name, Symbol::Flag::OmpDeclareSimd); 251 } 252 return true; 253 } 254 void Post(const parser::OpenMPDeclareSimdConstruct &) { PopContext(); } 255 bool Pre(const parser::OpenMPThreadprivate &); 256 void Post(const parser::OpenMPThreadprivate &) { PopContext(); } 257 258 // 2.15.3 Data-Sharing Attribute Clauses 259 void Post(const parser::OmpDefaultClause &); 260 bool Pre(const parser::OmpClause::Shared &x) { 261 ResolveOmpObjectList(x.v, Symbol::Flag::OmpShared); 262 return false; 263 } 264 bool Pre(const parser::OmpClause::Private &x) { 265 ResolveOmpObjectList(x.v, Symbol::Flag::OmpPrivate); 266 return false; 267 } 268 bool Pre(const parser::OmpAllocateClause &x) { 269 const auto &objectList{std::get<parser::OmpObjectList>(x.t)}; 270 ResolveOmpObjectList(objectList, Symbol::Flag::OmpAllocate); 271 return false; 272 } 273 bool Pre(const parser::OmpClause::Firstprivate &x) { 274 ResolveOmpObjectList(x.v, Symbol::Flag::OmpFirstPrivate); 275 return false; 276 } 277 bool Pre(const parser::OmpClause::Lastprivate &x) { 278 ResolveOmpObjectList(x.v, Symbol::Flag::OmpLastPrivate); 279 return false; 280 } 281 bool Pre(const parser::OmpClause::Copyin &x) { 282 ResolveOmpObjectList(x.v, Symbol::Flag::OmpCopyIn); 283 return false; 284 } 285 bool Pre(const parser::OmpLinearClause &x) { 286 std::visit(common::visitors{ 287 [&](const parser::OmpLinearClause::WithoutModifier 288 &linearWithoutModifier) { 289 ResolveOmpNameList( 290 linearWithoutModifier.names, Symbol::Flag::OmpLinear); 291 }, 292 [&](const parser::OmpLinearClause::WithModifier 293 &linearWithModifier) { 294 ResolveOmpNameList( 295 linearWithModifier.names, Symbol::Flag::OmpLinear); 296 }, 297 }, 298 x.u); 299 return false; 300 } 301 bool Pre(const parser::OmpAlignedClause &x) { 302 const auto &alignedNameList{std::get<std::list<parser::Name>>(x.t)}; 303 ResolveOmpNameList(alignedNameList, Symbol::Flag::OmpAligned); 304 return false; 305 } 306 void Post(const parser::Name &); 307 308 const parser::OmpClause *associatedClause{nullptr}; 309 void SetAssociatedClause(const parser::OmpClause &c) { 310 associatedClause = &c; 311 } 312 const parser::OmpClause *GetAssociatedClause() { return associatedClause; } 313 314 private: 315 std::int64_t GetAssociatedLoopLevelFromClauses(const parser::OmpClauseList &); 316 317 static constexpr Symbol::Flags dataSharingAttributeFlags{ 318 Symbol::Flag::OmpShared, Symbol::Flag::OmpPrivate, 319 Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate, 320 Symbol::Flag::OmpReduction, Symbol::Flag::OmpLinear}; 321 322 static constexpr Symbol::Flags privateDataSharingAttributeFlags{ 323 Symbol::Flag::OmpPrivate, Symbol::Flag::OmpFirstPrivate, 324 Symbol::Flag::OmpLastPrivate}; 325 326 static constexpr Symbol::Flags ompFlagsRequireNewSymbol{ 327 Symbol::Flag::OmpPrivate, Symbol::Flag::OmpLinear, 328 Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate, 329 Symbol::Flag::OmpReduction}; 330 331 static constexpr Symbol::Flags ompFlagsRequireMark{ 332 Symbol::Flag::OmpThreadprivate}; 333 334 static constexpr Symbol::Flags dataCopyingAttributeFlags{ 335 Symbol::Flag::OmpCopyIn}; 336 337 std::vector<const parser::Name *> allocateNames_; // on one directive 338 SymbolSet privateDataSharingAttributeObjects_; // on one directive 339 340 void AddAllocateName(const parser::Name *&object) { 341 allocateNames_.push_back(object); 342 } 343 void ClearAllocateNames() { allocateNames_.clear(); } 344 345 void AddPrivateDataSharingAttributeObjects(SymbolRef object) { 346 privateDataSharingAttributeObjects_.insert(object); 347 } 348 void ClearPrivateDataSharingAttributeObjects() { 349 privateDataSharingAttributeObjects_.clear(); 350 } 351 352 // Predetermined DSA rules 353 void PrivatizeAssociatedLoopIndexAndCheckLoopLevel( 354 const parser::OpenMPLoopConstruct &); 355 void ResolveSeqLoopIndexInParallelOrTaskConstruct(const parser::Name &); 356 357 void ResolveOmpObjectList(const parser::OmpObjectList &, Symbol::Flag); 358 void ResolveOmpObject(const parser::OmpObject &, Symbol::Flag); 359 Symbol *ResolveOmp(const parser::Name &, Symbol::Flag, Scope &); 360 Symbol *ResolveOmp(Symbol &, Symbol::Flag, Scope &); 361 Symbol *ResolveOmpCommonBlockName(const parser::Name *); 362 void ResolveOmpNameList(const std::list<parser::Name> &, Symbol::Flag); 363 void ResolveOmpName(const parser::Name &, Symbol::Flag); 364 Symbol *ResolveName(const parser::Name *); 365 Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag); 366 Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag); 367 void CheckMultipleAppearances( 368 const parser::Name &, const Symbol &, Symbol::Flag); 369 370 void CheckDataCopyingClause( 371 const parser::Name &, const Symbol &, Symbol::Flag); 372 373 void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause); 374 }; 375 376 template <typename T> 377 bool DirectiveAttributeVisitor<T>::HasDataSharingAttributeObject( 378 const Symbol &object) { 379 auto it{dataSharingAttributeObjects_.find(object)}; 380 return it != dataSharingAttributeObjects_.end(); 381 } 382 383 template <typename T> 384 const parser::Name &DirectiveAttributeVisitor<T>::GetLoopIndex( 385 const parser::DoConstruct &x) { 386 using Bounds = parser::LoopControl::Bounds; 387 return std::get<Bounds>(x.GetLoopControl()->u).name.thing; 388 } 389 390 template <typename T> 391 const parser::DoConstruct *DirectiveAttributeVisitor<T>::GetDoConstructIf( 392 const parser::ExecutionPartConstruct &x) { 393 return parser::Unwrap<parser::DoConstruct>(x); 394 } 395 396 template <typename T> 397 Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity( 398 const parser::Name &name, Symbol::Flag flag, Scope &scope) { 399 if (!name.symbol) { 400 return nullptr; // not resolved by Name Resolution step, do nothing 401 } 402 name.symbol = DeclarePrivateAccessEntity(*name.symbol, flag, scope); 403 return name.symbol; 404 } 405 406 template <typename T> 407 Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity( 408 Symbol &object, Symbol::Flag flag, Scope &scope) { 409 if (object.owner() != currScope()) { 410 auto &symbol{MakeAssocSymbol(object.name(), object, scope)}; 411 symbol.set(flag); 412 return &symbol; 413 } else { 414 object.set(flag); 415 return &object; 416 } 417 } 418 419 bool AccAttributeVisitor::Pre(const parser::OpenACCBlockConstruct &x) { 420 const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)}; 421 const auto &blockDir{std::get<parser::AccBlockDirective>(beginBlockDir.t)}; 422 switch (blockDir.v) { 423 case llvm::acc::Directive::ACCD_data: 424 case llvm::acc::Directive::ACCD_host_data: 425 case llvm::acc::Directive::ACCD_kernels: 426 case llvm::acc::Directive::ACCD_parallel: 427 case llvm::acc::Directive::ACCD_serial: 428 PushContext(blockDir.source, blockDir.v); 429 break; 430 default: 431 break; 432 } 433 ClearDataSharingAttributeObjects(); 434 return true; 435 } 436 437 bool AccAttributeVisitor::Pre(const parser::OpenACCLoopConstruct &x) { 438 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)}; 439 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)}; 440 const auto &clauseList{std::get<parser::AccClauseList>(beginDir.t)}; 441 if (loopDir.v == llvm::acc::Directive::ACCD_loop) { 442 PushContext(loopDir.source, loopDir.v); 443 } 444 ClearDataSharingAttributeObjects(); 445 SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList)); 446 PrivatizeAssociatedLoopIndex(x); 447 return true; 448 } 449 450 bool AccAttributeVisitor::Pre(const parser::OpenACCStandaloneConstruct &x) { 451 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)}; 452 switch (standaloneDir.v) { 453 case llvm::acc::Directive::ACCD_cache: 454 case llvm::acc::Directive::ACCD_enter_data: 455 case llvm::acc::Directive::ACCD_exit_data: 456 case llvm::acc::Directive::ACCD_init: 457 case llvm::acc::Directive::ACCD_set: 458 case llvm::acc::Directive::ACCD_shutdown: 459 case llvm::acc::Directive::ACCD_update: 460 PushContext(standaloneDir.source, standaloneDir.v); 461 break; 462 default: 463 break; 464 } 465 ClearDataSharingAttributeObjects(); 466 return true; 467 } 468 469 bool AccAttributeVisitor::Pre(const parser::OpenACCCombinedConstruct &x) { 470 const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)}; 471 const auto &combinedDir{ 472 std::get<parser::AccCombinedDirective>(beginBlockDir.t)}; 473 switch (combinedDir.v) { 474 case llvm::acc::Directive::ACCD_kernels_loop: 475 case llvm::acc::Directive::ACCD_parallel_loop: 476 case llvm::acc::Directive::ACCD_serial_loop: 477 PushContext(combinedDir.source, combinedDir.v); 478 break; 479 default: 480 break; 481 } 482 ClearDataSharingAttributeObjects(); 483 return true; 484 } 485 486 std::int64_t AccAttributeVisitor::GetAssociatedLoopLevelFromClauses( 487 const parser::AccClauseList &x) { 488 std::int64_t collapseLevel{0}; 489 for (const auto &clause : x.v) { 490 if (const auto *collapseClause{ 491 std::get_if<parser::AccClause::Collapse>(&clause.u)}) { 492 if (const auto v{EvaluateInt64(context_, collapseClause->v)}) { 493 collapseLevel = *v; 494 } 495 } 496 } 497 498 if (collapseLevel) { 499 return collapseLevel; 500 } 501 return 1; // default is outermost loop 502 } 503 504 void AccAttributeVisitor::PrivatizeAssociatedLoopIndex( 505 const parser::OpenACCLoopConstruct &x) { 506 std::int64_t level{GetContext().associatedLoopLevel}; 507 if (level <= 0) { // collpase value was negative or 0 508 return; 509 } 510 Symbol::Flag ivDSA{Symbol::Flag::AccPrivate}; 511 512 const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)}; 513 for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) { 514 // go through all the nested do-loops and resolve index variables 515 const parser::Name &iv{GetLoopIndex(*loop)}; 516 if (auto *symbol{ResolveAcc(iv, ivDSA, currScope())}) { 517 symbol->set(Symbol::Flag::AccPreDetermined); 518 iv.symbol = symbol; // adjust the symbol within region 519 AddToContextObjectWithDSA(*symbol, ivDSA); 520 } 521 522 const auto &block{std::get<parser::Block>(loop->t)}; 523 const auto it{block.begin()}; 524 loop = it != block.end() ? GetDoConstructIf(*it) : nullptr; 525 } 526 CHECK(level == 0); 527 } 528 529 void AccAttributeVisitor::Post(const parser::AccDefaultClause &x) { 530 if (!dirContext_.empty()) { 531 switch (x.v) { 532 case parser::AccDefaultClause::Arg::Present: 533 SetContextDefaultDSA(Symbol::Flag::AccPresent); 534 break; 535 case parser::AccDefaultClause::Arg::None: 536 SetContextDefaultDSA(Symbol::Flag::AccNone); 537 break; 538 } 539 } 540 } 541 542 // For OpenACC constructs, check all the data-refs within the constructs 543 // and adjust the symbol for each Name if necessary 544 void AccAttributeVisitor::Post(const parser::Name &name) { 545 auto *symbol{name.symbol}; 546 if (symbol && !dirContext_.empty() && GetContext().withinConstruct) { 547 if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() && 548 !IsObjectWithDSA(*symbol)) { 549 if (Symbol * found{currScope().FindSymbol(name.source)}) { 550 if (symbol != found) { 551 name.symbol = found; // adjust the symbol within region 552 } else if (GetContext().defaultDSA == Symbol::Flag::AccNone) { 553 // 2.5.14. 554 context_.Say(name.source, 555 "The DEFAULT(NONE) clause requires that '%s' must be listed in " 556 "a data-mapping clause"_err_en_US, 557 symbol->name()); 558 } 559 } 560 } 561 } // within OpenACC construct 562 } 563 564 Symbol *AccAttributeVisitor::ResolveAccCommonBlockName( 565 const parser::Name *name) { 566 if (!name) { 567 return nullptr; 568 } else if (auto *prev{ 569 GetContext().scope.parent().FindCommonBlock(name->source)}) { 570 name->symbol = prev; 571 return prev; 572 } else { 573 return nullptr; 574 } 575 } 576 577 void AccAttributeVisitor::ResolveAccObjectList( 578 const parser::AccObjectList &accObjectList, Symbol::Flag accFlag) { 579 for (const auto &accObject : accObjectList.v) { 580 ResolveAccObject(accObject, accFlag); 581 } 582 } 583 584 void AccAttributeVisitor::ResolveAccObject( 585 const parser::AccObject &accObject, Symbol::Flag accFlag) { 586 std::visit( 587 common::visitors{ 588 [&](const parser::Designator &designator) { 589 if (const auto *name{GetDesignatorNameIfDataRef(designator)}) { 590 if (auto *symbol{ResolveAcc(*name, accFlag, currScope())}) { 591 AddToContextObjectWithDSA(*symbol, accFlag); 592 if (dataSharingAttributeFlags.test(accFlag)) { 593 CheckMultipleAppearances(*name, *symbol, accFlag); 594 } 595 } 596 } else { 597 // Array sections to be changed to substrings as needed 598 if (AnalyzeExpr(context_, designator)) { 599 if (std::holds_alternative<parser::Substring>(designator.u)) { 600 context_.Say(designator.source, 601 "Substrings are not allowed on OpenACC " 602 "directives or clauses"_err_en_US); 603 } 604 } 605 // other checks, more TBD 606 } 607 }, 608 [&](const parser::Name &name) { // common block 609 if (auto *symbol{ResolveAccCommonBlockName(&name)}) { 610 CheckMultipleAppearances( 611 name, *symbol, Symbol::Flag::AccCommonBlock); 612 for (auto &object : symbol->get<CommonBlockDetails>().objects()) { 613 if (auto *resolvedObject{ 614 ResolveAcc(*object, accFlag, currScope())}) { 615 AddToContextObjectWithDSA(*resolvedObject, accFlag); 616 } 617 } 618 } else { 619 context_.Say(name.source, 620 "COMMON block must be declared in the same scoping unit " 621 "in which the OpenACC directive or clause appears"_err_en_US); 622 } 623 }, 624 }, 625 accObject.u); 626 } 627 628 Symbol *AccAttributeVisitor::ResolveAcc( 629 const parser::Name &name, Symbol::Flag accFlag, Scope &scope) { 630 if (accFlagsRequireNewSymbol.test(accFlag)) { 631 return DeclarePrivateAccessEntity(name, accFlag, scope); 632 } else { 633 return DeclareOrMarkOtherAccessEntity(name, accFlag); 634 } 635 } 636 637 Symbol *AccAttributeVisitor::ResolveAcc( 638 Symbol &symbol, Symbol::Flag accFlag, Scope &scope) { 639 if (accFlagsRequireNewSymbol.test(accFlag)) { 640 return DeclarePrivateAccessEntity(symbol, accFlag, scope); 641 } else { 642 return DeclareOrMarkOtherAccessEntity(symbol, accFlag); 643 } 644 } 645 646 Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity( 647 const parser::Name &name, Symbol::Flag accFlag) { 648 Symbol *prev{currScope().FindSymbol(name.source)}; 649 if (!name.symbol || !prev) { 650 return nullptr; 651 } else if (prev != name.symbol) { 652 name.symbol = prev; 653 } 654 return DeclareOrMarkOtherAccessEntity(*prev, accFlag); 655 } 656 657 Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity( 658 Symbol &object, Symbol::Flag accFlag) { 659 if (accFlagsRequireMark.test(accFlag)) { 660 object.set(accFlag); 661 } 662 return &object; 663 } 664 665 static bool WithMultipleAppearancesAccException( 666 const Symbol &symbol, Symbol::Flag flag) { 667 return false; // Place holder 668 } 669 670 void AccAttributeVisitor::CheckMultipleAppearances( 671 const parser::Name &name, const Symbol &symbol, Symbol::Flag accFlag) { 672 const auto *target{&symbol}; 673 if (accFlagsRequireNewSymbol.test(accFlag)) { 674 if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) { 675 target = &details->symbol(); 676 } 677 } 678 if (HasDataSharingAttributeObject(*target) && 679 !WithMultipleAppearancesAccException(symbol, accFlag)) { 680 context_.Say(name.source, 681 "'%s' appears in more than one data-sharing clause " 682 "on the same OpenACC directive"_err_en_US, 683 name.ToString()); 684 } else { 685 AddDataSharingAttributeObject(*target); 686 } 687 } 688 689 bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) { 690 const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)}; 691 const auto &beginDir{std::get<parser::OmpBlockDirective>(beginBlockDir.t)}; 692 switch (beginDir.v) { 693 case llvm::omp::Directive::OMPD_master: 694 case llvm::omp::Directive::OMPD_ordered: 695 case llvm::omp::Directive::OMPD_parallel: 696 case llvm::omp::Directive::OMPD_single: 697 case llvm::omp::Directive::OMPD_target: 698 case llvm::omp::Directive::OMPD_target_data: 699 case llvm::omp::Directive::OMPD_task: 700 case llvm::omp::Directive::OMPD_teams: 701 case llvm::omp::Directive::OMPD_workshare: 702 case llvm::omp::Directive::OMPD_parallel_workshare: 703 case llvm::omp::Directive::OMPD_target_teams: 704 case llvm::omp::Directive::OMPD_target_parallel: 705 PushContext(beginDir.source, beginDir.v); 706 break; 707 default: 708 // TODO others 709 break; 710 } 711 ClearDataSharingAttributeObjects(); 712 ClearPrivateDataSharingAttributeObjects(); 713 ClearAllocateNames(); 714 return true; 715 } 716 717 void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) { 718 const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)}; 719 const auto &beginDir{std::get<parser::OmpBlockDirective>(beginBlockDir.t)}; 720 switch (beginDir.v) { 721 case llvm::omp::Directive::OMPD_parallel: 722 case llvm::omp::Directive::OMPD_single: 723 case llvm::omp::Directive::OMPD_target: 724 case llvm::omp::Directive::OMPD_task: 725 case llvm::omp::Directive::OMPD_teams: 726 case llvm::omp::Directive::OMPD_parallel_workshare: 727 case llvm::omp::Directive::OMPD_target_teams: 728 case llvm::omp::Directive::OMPD_target_parallel: { 729 bool hasPrivate; 730 for (const auto *allocName : allocateNames_) { 731 hasPrivate = false; 732 for (auto privateObj : privateDataSharingAttributeObjects_) { 733 const Symbol &symbolPrivate{*privateObj}; 734 if (allocName->source == symbolPrivate.name()) { 735 hasPrivate = true; 736 break; 737 } 738 } 739 if (!hasPrivate) { 740 context_.Say(allocName->source, 741 "The ALLOCATE clause requires that '%s' must be listed in a " 742 "private " 743 "data-sharing attribute clause on the same directive"_err_en_US, 744 allocName->ToString()); 745 } 746 } 747 break; 748 } 749 default: 750 break; 751 } 752 PopContext(); 753 } 754 755 bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) { 756 const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)}; 757 const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)}; 758 const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)}; 759 switch (beginDir.v) { 760 case llvm::omp::Directive::OMPD_distribute: 761 case llvm::omp::Directive::OMPD_distribute_parallel_do: 762 case llvm::omp::Directive::OMPD_distribute_parallel_do_simd: 763 case llvm::omp::Directive::OMPD_distribute_simd: 764 case llvm::omp::Directive::OMPD_do: 765 case llvm::omp::Directive::OMPD_do_simd: 766 case llvm::omp::Directive::OMPD_parallel_do: 767 case llvm::omp::Directive::OMPD_parallel_do_simd: 768 case llvm::omp::Directive::OMPD_simd: 769 case llvm::omp::Directive::OMPD_target_parallel_do: 770 case llvm::omp::Directive::OMPD_target_parallel_do_simd: 771 case llvm::omp::Directive::OMPD_target_teams_distribute: 772 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do: 773 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: 774 case llvm::omp::Directive::OMPD_target_teams_distribute_simd: 775 case llvm::omp::Directive::OMPD_target_simd: 776 case llvm::omp::Directive::OMPD_taskloop: 777 case llvm::omp::Directive::OMPD_taskloop_simd: 778 case llvm::omp::Directive::OMPD_teams_distribute: 779 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do: 780 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd: 781 case llvm::omp::Directive::OMPD_teams_distribute_simd: 782 PushContext(beginDir.source, beginDir.v); 783 break; 784 default: 785 break; 786 } 787 ClearDataSharingAttributeObjects(); 788 SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList)); 789 PrivatizeAssociatedLoopIndexAndCheckLoopLevel(x); 790 return true; 791 } 792 793 void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct( 794 const parser::Name &iv) { 795 auto targetIt{dirContext_.rbegin()}; 796 for (;; ++targetIt) { 797 if (targetIt == dirContext_.rend()) { 798 return; 799 } 800 if (llvm::omp::parallelSet.test(targetIt->directive) || 801 llvm::omp::taskGeneratingSet.test(targetIt->directive)) { 802 break; 803 } 804 } 805 if (auto *symbol{ResolveOmp(iv, Symbol::Flag::OmpPrivate, targetIt->scope)}) { 806 targetIt++; 807 symbol->set(Symbol::Flag::OmpPreDetermined); 808 iv.symbol = symbol; // adjust the symbol within region 809 for (auto it{dirContext_.rbegin()}; it != targetIt; ++it) { 810 AddToContextObjectWithDSA(*symbol, Symbol::Flag::OmpPrivate, *it); 811 } 812 } 813 } 814 815 // 2.15.1.1 Data-sharing Attribute Rules - Predetermined 816 // - A loop iteration variable for a sequential loop in a parallel 817 // or task generating construct is private in the innermost such 818 // construct that encloses the loop 819 bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) { 820 if (!dirContext_.empty() && GetContext().withinConstruct) { 821 if (const auto &iv{GetLoopIndex(x)}; iv.symbol) { 822 if (!iv.symbol->test(Symbol::Flag::OmpPreDetermined)) { 823 ResolveSeqLoopIndexInParallelOrTaskConstruct(iv); 824 } else { 825 // TODO: conflict checks with explicitly determined DSA 826 } 827 } 828 } 829 return true; 830 } 831 832 std::int64_t OmpAttributeVisitor::GetAssociatedLoopLevelFromClauses( 833 const parser::OmpClauseList &x) { 834 std::int64_t orderedLevel{0}; 835 std::int64_t collapseLevel{0}; 836 837 const parser::OmpClause *ordClause{nullptr}; 838 const parser::OmpClause *collClause{nullptr}; 839 840 for (const auto &clause : x.v) { 841 if (const auto *orderedClause{ 842 std::get_if<parser::OmpClause::Ordered>(&clause.u)}) { 843 if (const auto v{EvaluateInt64(context_, orderedClause->v)}) { 844 orderedLevel = *v; 845 } 846 ordClause = &clause; 847 } 848 if (const auto *collapseClause{ 849 std::get_if<parser::OmpClause::Collapse>(&clause.u)}) { 850 if (const auto v{EvaluateInt64(context_, collapseClause->v)}) { 851 collapseLevel = *v; 852 } 853 collClause = &clause; 854 } 855 } 856 857 if (orderedLevel && (!collapseLevel || orderedLevel >= collapseLevel)) { 858 SetAssociatedClause(*ordClause); 859 return orderedLevel; 860 } else if (!orderedLevel && collapseLevel) { 861 SetAssociatedClause(*collClause); 862 return collapseLevel; 863 } // orderedLevel < collapseLevel is an error handled in structural checks 864 return 1; // default is outermost loop 865 } 866 867 // 2.15.1.1 Data-sharing Attribute Rules - Predetermined 868 // - The loop iteration variable(s) in the associated do-loop(s) of a do, 869 // parallel do, taskloop, or distribute construct is (are) private. 870 // - The loop iteration variable in the associated do-loop of a simd construct 871 // with just one associated do-loop is linear with a linear-step that is the 872 // increment of the associated do-loop. 873 // - The loop iteration variables in the associated do-loops of a simd 874 // construct with multiple associated do-loops are lastprivate. 875 void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel( 876 const parser::OpenMPLoopConstruct &x) { 877 std::int64_t level{GetContext().associatedLoopLevel}; 878 if (level <= 0) { 879 return; 880 } 881 Symbol::Flag ivDSA; 882 if (!llvm::omp::simdSet.test(GetContext().directive)) { 883 ivDSA = Symbol::Flag::OmpPrivate; 884 } else if (level == 1) { 885 ivDSA = Symbol::Flag::OmpLinear; 886 } else { 887 ivDSA = Symbol::Flag::OmpLastPrivate; 888 } 889 890 const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)}; 891 for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) { 892 // go through all the nested do-loops and resolve index variables 893 const parser::Name &iv{GetLoopIndex(*loop)}; 894 if (auto *symbol{ResolveOmp(iv, ivDSA, currScope())}) { 895 symbol->set(Symbol::Flag::OmpPreDetermined); 896 iv.symbol = symbol; // adjust the symbol within region 897 AddToContextObjectWithDSA(*symbol, ivDSA); 898 } 899 900 const auto &block{std::get<parser::Block>(loop->t)}; 901 const auto it{block.begin()}; 902 loop = it != block.end() ? GetDoConstructIf(*it) : nullptr; 903 } 904 CheckAssocLoopLevel(level, GetAssociatedClause()); 905 } 906 void OmpAttributeVisitor::CheckAssocLoopLevel( 907 std::int64_t level, const parser::OmpClause *clause) { 908 if (clause && level != 0) { 909 context_.Say(clause->source, 910 "The value of the parameter in the COLLAPSE or ORDERED clause must" 911 " not be larger than the number of nested loops" 912 " following the construct."_err_en_US); 913 } 914 } 915 916 bool OmpAttributeVisitor::Pre(const parser::OpenMPSectionsConstruct &x) { 917 const auto &beginSectionsDir{ 918 std::get<parser::OmpBeginSectionsDirective>(x.t)}; 919 const auto &beginDir{ 920 std::get<parser::OmpSectionsDirective>(beginSectionsDir.t)}; 921 switch (beginDir.v) { 922 case llvm::omp::Directive::OMPD_parallel_sections: 923 case llvm::omp::Directive::OMPD_sections: 924 PushContext(beginDir.source, beginDir.v); 925 break; 926 default: 927 break; 928 } 929 ClearDataSharingAttributeObjects(); 930 return true; 931 } 932 933 bool OmpAttributeVisitor::Pre(const parser::OpenMPThreadprivate &x) { 934 PushContext(x.source, llvm::omp::Directive::OMPD_threadprivate); 935 const auto &list{std::get<parser::OmpObjectList>(x.t)}; 936 ResolveOmpObjectList(list, Symbol::Flag::OmpThreadprivate); 937 return true; 938 } 939 940 void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) { 941 if (!dirContext_.empty()) { 942 switch (x.v) { 943 case parser::OmpDefaultClause::Type::Private: 944 SetContextDefaultDSA(Symbol::Flag::OmpPrivate); 945 break; 946 case parser::OmpDefaultClause::Type::Firstprivate: 947 SetContextDefaultDSA(Symbol::Flag::OmpFirstPrivate); 948 break; 949 case parser::OmpDefaultClause::Type::Shared: 950 SetContextDefaultDSA(Symbol::Flag::OmpShared); 951 break; 952 case parser::OmpDefaultClause::Type::None: 953 SetContextDefaultDSA(Symbol::Flag::OmpNone); 954 break; 955 } 956 } 957 } 958 959 // For OpenMP constructs, check all the data-refs within the constructs 960 // and adjust the symbol for each Name if necessary 961 void OmpAttributeVisitor::Post(const parser::Name &name) { 962 auto *symbol{name.symbol}; 963 if (symbol && !dirContext_.empty() && GetContext().withinConstruct) { 964 if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() && 965 !IsObjectWithDSA(*symbol)) { 966 // TODO: create a separate function to go through the rules for 967 // predetermined, explicitly determined, and implicitly 968 // determined data-sharing attributes (2.15.1.1). 969 if (Symbol * found{currScope().FindSymbol(name.source)}) { 970 if (symbol != found) { 971 name.symbol = found; // adjust the symbol within region 972 } else if (GetContext().defaultDSA == Symbol::Flag::OmpNone) { 973 context_.Say(name.source, 974 "The DEFAULT(NONE) clause requires that '%s' must be listed in " 975 "a data-sharing attribute clause"_err_en_US, 976 symbol->name()); 977 } 978 } 979 } 980 } // within OpenMP construct 981 } 982 983 Symbol *OmpAttributeVisitor::ResolveName(const parser::Name *name) { 984 if (auto *resolvedSymbol{ 985 name ? GetContext().scope.FindSymbol(name->source) : nullptr}) { 986 name->symbol = resolvedSymbol; 987 return resolvedSymbol; 988 } else { 989 return nullptr; 990 } 991 } 992 993 void OmpAttributeVisitor::ResolveOmpName( 994 const parser::Name &name, Symbol::Flag ompFlag) { 995 if (ResolveName(&name)) { 996 if (auto *resolvedSymbol{ResolveOmp(name, ompFlag, currScope())}) { 997 if (dataSharingAttributeFlags.test(ompFlag)) { 998 AddToContextObjectWithDSA(*resolvedSymbol, ompFlag); 999 } 1000 } 1001 } 1002 } 1003 1004 void OmpAttributeVisitor::ResolveOmpNameList( 1005 const std::list<parser::Name> &nameList, Symbol::Flag ompFlag) { 1006 for (const auto &name : nameList) { 1007 ResolveOmpName(name, ompFlag); 1008 } 1009 } 1010 1011 Symbol *OmpAttributeVisitor::ResolveOmpCommonBlockName( 1012 const parser::Name *name) { 1013 if (auto *prev{name 1014 ? GetContext().scope.parent().FindCommonBlock(name->source) 1015 : nullptr}) { 1016 name->symbol = prev; 1017 return prev; 1018 } 1019 // Check if the Common Block is declared in the current scope 1020 if (auto *commonBlockSymbol{ 1021 name ? GetContext().scope.FindCommonBlock(name->source) : nullptr}) { 1022 name->symbol = commonBlockSymbol; 1023 return commonBlockSymbol; 1024 } 1025 return nullptr; 1026 } 1027 1028 void OmpAttributeVisitor::ResolveOmpObjectList( 1029 const parser::OmpObjectList &ompObjectList, Symbol::Flag ompFlag) { 1030 for (const auto &ompObject : ompObjectList.v) { 1031 ResolveOmpObject(ompObject, ompFlag); 1032 } 1033 } 1034 1035 void OmpAttributeVisitor::ResolveOmpObject( 1036 const parser::OmpObject &ompObject, Symbol::Flag ompFlag) { 1037 std::visit( 1038 common::visitors{ 1039 [&](const parser::Designator &designator) { 1040 if (const auto *name{GetDesignatorNameIfDataRef(designator)}) { 1041 if (auto *symbol{ResolveOmp(*name, ompFlag, currScope())}) { 1042 if (dataCopyingAttributeFlags.test(ompFlag)) { 1043 CheckDataCopyingClause(*name, *symbol, ompFlag); 1044 } else { 1045 AddToContextObjectWithDSA(*symbol, ompFlag); 1046 if (dataSharingAttributeFlags.test(ompFlag)) { 1047 CheckMultipleAppearances(*name, *symbol, ompFlag); 1048 } 1049 if (ompFlag == Symbol::Flag::OmpAllocate) { 1050 AddAllocateName(name); 1051 } 1052 } 1053 } 1054 } else { 1055 // Array sections to be changed to substrings as needed 1056 if (AnalyzeExpr(context_, designator)) { 1057 if (std::holds_alternative<parser::Substring>(designator.u)) { 1058 context_.Say(designator.source, 1059 "Substrings are not allowed on OpenMP " 1060 "directives or clauses"_err_en_US); 1061 } 1062 } 1063 // other checks, more TBD 1064 } 1065 }, 1066 [&](const parser::Name &name) { // common block 1067 if (auto *symbol{ResolveOmpCommonBlockName(&name)}) { 1068 if (!dataCopyingAttributeFlags.test(ompFlag)) { 1069 CheckMultipleAppearances( 1070 name, *symbol, Symbol::Flag::OmpCommonBlock); 1071 } 1072 // 2.15.3 When a named common block appears in a list, it has the 1073 // same meaning as if every explicit member of the common block 1074 // appeared in the list 1075 for (auto &object : symbol->get<CommonBlockDetails>().objects()) { 1076 if (auto *resolvedObject{ 1077 ResolveOmp(*object, ompFlag, currScope())}) { 1078 if (dataCopyingAttributeFlags.test(ompFlag)) { 1079 CheckDataCopyingClause(name, *resolvedObject, ompFlag); 1080 } else { 1081 AddToContextObjectWithDSA(*resolvedObject, ompFlag); 1082 } 1083 } 1084 } 1085 } else { 1086 context_.Say(name.source, // 2.15.3 1087 "COMMON block must be declared in the same scoping unit " 1088 "in which the OpenMP directive or clause appears"_err_en_US); 1089 } 1090 }, 1091 }, 1092 ompObject.u); 1093 } 1094 1095 Symbol *OmpAttributeVisitor::ResolveOmp( 1096 const parser::Name &name, Symbol::Flag ompFlag, Scope &scope) { 1097 if (ompFlagsRequireNewSymbol.test(ompFlag)) { 1098 return DeclarePrivateAccessEntity(name, ompFlag, scope); 1099 } else { 1100 return DeclareOrMarkOtherAccessEntity(name, ompFlag); 1101 } 1102 } 1103 1104 Symbol *OmpAttributeVisitor::ResolveOmp( 1105 Symbol &symbol, Symbol::Flag ompFlag, Scope &scope) { 1106 if (ompFlagsRequireNewSymbol.test(ompFlag)) { 1107 return DeclarePrivateAccessEntity(symbol, ompFlag, scope); 1108 } else { 1109 return DeclareOrMarkOtherAccessEntity(symbol, ompFlag); 1110 } 1111 } 1112 1113 Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity( 1114 const parser::Name &name, Symbol::Flag ompFlag) { 1115 Symbol *prev{currScope().FindSymbol(name.source)}; 1116 if (!name.symbol || !prev) { 1117 return nullptr; 1118 } else if (prev != name.symbol) { 1119 name.symbol = prev; 1120 } 1121 return DeclareOrMarkOtherAccessEntity(*prev, ompFlag); 1122 } 1123 1124 Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity( 1125 Symbol &object, Symbol::Flag ompFlag) { 1126 if (ompFlagsRequireMark.test(ompFlag)) { 1127 object.set(ompFlag); 1128 } 1129 return &object; 1130 } 1131 1132 static bool WithMultipleAppearancesOmpException( 1133 const Symbol &symbol, Symbol::Flag flag) { 1134 return (flag == Symbol::Flag::OmpFirstPrivate && 1135 symbol.test(Symbol::Flag::OmpLastPrivate)) || 1136 (flag == Symbol::Flag::OmpLastPrivate && 1137 symbol.test(Symbol::Flag::OmpFirstPrivate)); 1138 } 1139 1140 void OmpAttributeVisitor::CheckMultipleAppearances( 1141 const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) { 1142 const auto *target{&symbol}; 1143 if (ompFlagsRequireNewSymbol.test(ompFlag)) { 1144 if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) { 1145 target = &details->symbol(); 1146 } 1147 } 1148 if (HasDataSharingAttributeObject(*target) && 1149 !WithMultipleAppearancesOmpException(symbol, ompFlag)) { 1150 context_.Say(name.source, 1151 "'%s' appears in more than one data-sharing clause " 1152 "on the same OpenMP directive"_err_en_US, 1153 name.ToString()); 1154 } else { 1155 AddDataSharingAttributeObject(*target); 1156 if (privateDataSharingAttributeFlags.test(ompFlag)) { 1157 AddPrivateDataSharingAttributeObjects(*target); 1158 } 1159 } 1160 } 1161 1162 void ResolveAccParts( 1163 SemanticsContext &context, const parser::ProgramUnit &node) { 1164 if (context.IsEnabled(common::LanguageFeature::OpenACC)) { 1165 AccAttributeVisitor{context}.Walk(node); 1166 } 1167 } 1168 1169 void ResolveOmpParts( 1170 SemanticsContext &context, const parser::ProgramUnit &node) { 1171 if (context.IsEnabled(common::LanguageFeature::OpenMP)) { 1172 OmpAttributeVisitor{context}.Walk(node); 1173 if (!context.AnyFatalError()) { 1174 // The data-sharing attribute of the loop iteration variable for a 1175 // sequential loop (2.15.1.1) can only be determined when visiting 1176 // the corresponding DoConstruct, a second walk is to adjust the 1177 // symbols for all the data-refs of that loop iteration variable 1178 // prior to the DoConstruct. 1179 OmpAttributeVisitor{context}.Walk(node); 1180 } 1181 } 1182 } 1183 1184 void OmpAttributeVisitor::CheckDataCopyingClause( 1185 const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) { 1186 const auto *checkSymbol{&symbol}; 1187 if (ompFlag == Symbol::Flag::OmpCopyIn) { 1188 if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) 1189 checkSymbol = &details->symbol(); 1190 1191 // List of items/objects that can appear in a 'copyin' clause must be 1192 // 'threadprivate' 1193 if (!checkSymbol->test(Symbol::Flag::OmpThreadprivate)) 1194 context_.Say(name.source, 1195 "Non-THREADPRIVATE object '%s' in COPYIN clause"_err_en_US, 1196 checkSymbol->name()); 1197 } 1198 } 1199 1200 } // namespace Fortran::semantics 1201