@@ -388,6 +388,29 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
388388 explicit OmpAttributeVisitor (SemanticsContext &context)
389389 : DirectiveAttributeVisitor(context) {}
390390
391+ static bool HasStaticStorageDuration (const Symbol &symbol) {
392+ auto &ultSym = symbol.GetUltimate ();
393+ // Module-scope variable
394+ return ultSym.owner ().kind () == Scope::Kind::Module ||
395+ // Data statement variable
396+ ultSym.flags ().test (Symbol::Flag::InDataStmt) ||
397+ // Save attribute variable
398+ ultSym.attrs ().test (Attr::SAVE) ||
399+ // Referenced in a common block
400+ ultSym.flags ().test (Symbol::Flag::InCommonBlock);
401+ }
402+
403+ // Recognize symbols that are not created as a part of the OpenMP data-
404+ // sharing processing, and that are declared inside of the construct.
405+ // These symbols are predetermined private, but they shouldn't be marked
406+ // in any special way, because there is nothing to be done for them.
407+ // They are not symbols for which private copies need to be created,
408+ // they are already themselves private.
409+ static bool IsLocalInsideScope (const Symbol &symbol, const Scope &scope) {
410+ return symbol.owner () != scope && scope.Contains (symbol.owner ()) &&
411+ !HasStaticStorageDuration (symbol);
412+ }
413+
391414 template <typename A> void Walk (const A &x) { parser::Walk (x, *this ); }
392415 template <typename A> bool Pre (const A &) { return true ; }
393416 template <typename A> void Post (const A &) {}
@@ -2076,6 +2099,9 @@ void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct(
20762099 break ;
20772100 }
20782101 }
2102+ if (IsLocalInsideScope (*iv.symbol , targetIt->scope )) {
2103+ return ;
2104+ }
20792105 // If this symbol already has a data-sharing attribute then there is nothing
20802106 // to do here.
20812107 if (const Symbol * symbol{iv.symbol }) {
@@ -2400,14 +2426,14 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel(
24002426 }
24012427 }
24022428 // go through all the nested do-loops and resolve index variables
2403- const parser::Name *iv{GetLoopIndex (*loop)};
2404- if (iv) {
2405- if (auto *symbol{ResolveOmp (*iv, ivDSA, currScope ())}) {
2406- SetSymbolDSA (*symbol, {Symbol::Flag::OmpPreDetermined, ivDSA});
2407- iv->symbol = symbol; // adjust the symbol within region
2408- AddToContextObjectWithDSA (*symbol, ivDSA);
2429+ if (const parser::Name *iv{GetLoopIndex (*loop)}) {
2430+ if (!iv->symbol || !IsLocalInsideScope (*iv->symbol , currScope ())) {
2431+ if (auto *symbol{ResolveOmp (*iv, ivDSA, currScope ())}) {
2432+ SetSymbolDSA (*symbol, {Symbol::Flag::OmpPreDetermined, ivDSA});
2433+ iv->symbol = symbol; // adjust the symbol within region
2434+ AddToContextObjectWithDSA (*symbol, ivDSA);
2435+ }
24092436 }
2410-
24112437 const auto &block{std::get<parser::Block>(loop->t )};
24122438 const auto it{block.begin ()};
24132439 loop = it != block.end () ? GetDoConstructIf (*it) : nullptr ;
@@ -2651,20 +2677,6 @@ static bool IsPrivatizable(const Symbol *sym) {
26512677 misc->kind () != MiscDetails::Kind::ConstructName));
26522678}
26532679
2654- static bool IsSymbolStaticStorageDuration (const Symbol &symbol) {
2655- LLVM_DEBUG (llvm::dbgs () << " IsSymbolStaticStorageDuration(" << symbol.name ()
2656- << " ):\n " );
2657- auto ultSym = symbol.GetUltimate ();
2658- // Module-scope variable
2659- return (ultSym.owner ().kind () == Scope::Kind::Module) ||
2660- // Data statement variable
2661- (ultSym.flags ().test (Symbol::Flag::InDataStmt)) ||
2662- // Save attribute variable
2663- (ultSym.attrs ().test (Attr::SAVE)) ||
2664- // Referenced in a common block
2665- (ultSym.flags ().test (Symbol::Flag::InCommonBlock));
2666- }
2667-
26682680static bool IsTargetCaptureImplicitlyFirstprivatizeable (const Symbol &symbol,
26692681 const Symbol::Flags &dsa, const Symbol::Flags &dataSharingAttributeFlags,
26702682 const Symbol::Flags &dataMappingAttributeFlags,
@@ -2823,7 +2835,9 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
28232835 bool targetDir = llvm::omp::allTargetSet.test (dirContext.directive );
28242836 bool parallelDir = llvm::omp::topParallelSet.test (dirContext.directive );
28252837 bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
2826- bool isStaticStorageDuration = IsSymbolStaticStorageDuration (*symbol);
2838+ bool isStaticStorageDuration = HasStaticStorageDuration (*symbol);
2839+ LLVM_DEBUG (llvm::dbgs ()
2840+ << " HasStaticStorageDuration(" << symbol->name () << " ):\n " );
28272841
28282842 if (dsa.any ()) {
28292843 if (parallelDir || taskGenDir || teamsDir) {
@@ -2977,7 +2991,8 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
29772991 auto *symbol{name.symbol };
29782992
29792993 if (symbol && WithinConstruct ()) {
2980- if (IsPrivatizable (symbol) && !IsObjectWithDSA (*symbol)) {
2994+ if (IsPrivatizable (symbol) && !IsObjectWithDSA (*symbol) &&
2995+ !IsLocalInsideScope (*symbol, currScope ())) {
29812996 // TODO: create a separate function to go through the rules for
29822997 // predetermined, explicitly determined, and implicitly
29832998 // determined data-sharing attributes (2.15.1.1).
@@ -3046,7 +3061,17 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
30463061 return ;
30473062 }
30483063
3049- CreateImplicitSymbols (symbol);
3064+ // We should only create any additional symbols, if the one mentioned
3065+ // in the source code was declared outside of the construct. This was
3066+ // always the case before Fortran 2008. F2008 introduced the BLOCK
3067+ // construct, and allowed local variable declarations.
3068+ // In OpenMP local (non-static) variables are always private in a given
3069+ // construct, if they are declared inside the construct. In those cases
3070+ // we don't need to do anything here (i.e. no flags are needed or
3071+ // anything else).
3072+ if (!IsLocalInsideScope (*symbol, currScope ())) {
3073+ CreateImplicitSymbols (symbol);
3074+ }
30503075 } // within OpenMP construct
30513076}
30523077
0 commit comments