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