19
19
#include " flang/Parser/parse-tree.h"
20
20
#include " flang/Parser/tools.h"
21
21
#include " flang/Semantics/expression.h"
22
- #include " flang/Semantics/tools.h"
23
22
#include < list>
24
23
#include < map>
25
24
#include < sstream>
@@ -730,6 +729,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
730
729
void CheckNameInAllocateStmt (const parser::CharBlock &source,
731
730
const parser::Name &ompObject, const parser::AllocateStmt &allocate);
732
731
732
+ bool HasSymbolInEnclosingScope (const Symbol &, Scope &);
733
733
std::int64_t ordCollapseLevel{0 };
734
734
735
735
void AddOmpRequiresToScope (Scope &, WithOmpDeclarative::RequiresFlags,
@@ -2085,22 +2085,16 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
2085
2085
}
2086
2086
}
2087
2087
2088
- // When handling each implicit rule for a given symbol, one of the
2089
- // following 3 actions may be taken:
2090
- // 1. Declare a new private symbol.
2091
- // 2. Create a new association symbol with no flags, that will represent
2092
- // a shared symbol in the current scope. Note that symbols without
2093
- // any private flags are considered as shared.
2094
- // 3. Use the last declared private symbol, by inserting a new symbol
2095
- // in the scope being processed, associated with it.
2096
- // If no private symbol was declared previously, then no association
2097
- // is needed and the symbol from the enclosing scope will be
2098
- // inherited by the current one.
2099
- //
2100
- // Because of how symbols are collected in lowering, not inserting a new
2101
- // symbol in the last case could lead to the conclusion that a symbol
2102
- // from an enclosing construct was declared in the current construct,
2103
- // which would result in wrong privatization code being generated.
2088
+ // When handling each implicit rule, either a new private symbol is
2089
+ // declared or the last declared symbol is used.
2090
+ // In the latter case, it's necessary to insert a new symbol in the scope
2091
+ // being processed, associated with the last declared symbol.
2092
+ // This captures the fact that, although we are using the last declared
2093
+ // symbol, its DSA could be different in this scope.
2094
+ // Also, because of how symbols are collected in lowering, not inserting
2095
+ // a new symbol in this scope could lead to the conclusion that the
2096
+ // symbol was declared in this construct, which would result in wrong
2097
+ // privatization code being generated.
2104
2098
// Consider the following example:
2105
2099
//
2106
2100
// !$omp parallel default(private) ! p1
@@ -2113,56 +2107,48 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
2113
2107
// (p2), it would use the x symbol definition from the enclosing scope.
2114
2108
// Then, when p2's default symbols were collected in lowering, the x
2115
2109
// symbol from the outer parallel construct (p1) would be collected, as
2116
- // it would have the private flag set.
2110
+ // it would have the private flag set (note that symbols that don't have
2111
+ // any private flag are considered as shared).
2117
2112
// This would make x appear to be defined in p2, causing it to be
2118
2113
// privatized in p2 and its privatization in p1 to be skipped.
2119
- auto makePrivateSymbol = [&](Symbol::Flag flag) {
2114
+ auto declNewSymbol = [&](Symbol::Flag flag) {
2120
2115
Symbol *hostSymbol =
2121
2116
lastDeclSymbol ? lastDeclSymbol : &symbol->GetUltimate ();
2122
2117
lastDeclSymbol = DeclarePrivateAccessEntity (
2123
2118
*hostSymbol, flag, context_.FindScope (dirContext.directiveSource ));
2124
2119
return lastDeclSymbol;
2125
2120
};
2126
- auto makeSharedSymbol = [&]() {
2127
- Symbol *hostSymbol =
2128
- lastDeclSymbol ? lastDeclSymbol : &symbol->GetUltimate ();
2129
- MakeAssocSymbol (symbol->name (), *hostSymbol,
2130
- context_.FindScope (dirContext.directiveSource ));
2131
- };
2132
2121
auto useLastDeclSymbol = [&]() {
2133
2122
if (lastDeclSymbol)
2134
2123
MakeAssocSymbol (symbol->name (), *lastDeclSymbol,
2135
2124
context_.FindScope (dirContext.directiveSource ));
2136
2125
};
2137
2126
2138
- bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
2139
- bool targetDir = llvm::omp::allTargetSet.test (dirContext.directive );
2140
- bool parallelDir = llvm::omp::allParallelSet.test (dirContext.directive );
2141
- bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
2142
-
2143
2127
if (dsa.has_value ()) {
2144
- if (dsa.value () == Symbol::Flag::OmpShared &&
2145
- (parallelDir || taskGenDir || teamsDir))
2146
- makeSharedSymbol ();
2147
- // Private symbols will have been declared already.
2128
+ useLastDeclSymbol ();
2148
2129
prevDSA = dsa;
2149
2130
continue ;
2150
2131
}
2151
2132
2133
+ bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
2134
+ bool targetDir = llvm::omp::allTargetSet.test (dirContext.directive );
2135
+ bool parallelDir = llvm::omp::allParallelSet.test (dirContext.directive );
2136
+
2152
2137
if (dirContext.defaultDSA == Symbol::Flag::OmpPrivate ||
2153
2138
dirContext.defaultDSA == Symbol::Flag::OmpFirstPrivate ||
2154
2139
dirContext.defaultDSA == Symbol::Flag::OmpShared) {
2155
2140
// 1) default
2156
2141
// Allowed only with parallel, teams and task generating constructs.
2157
- assert (parallelDir || taskGenDir || teamsDir);
2142
+ assert (parallelDir || taskGenDir ||
2143
+ llvm::omp::allTeamsSet.test (dirContext.directive ));
2158
2144
if (dirContext.defaultDSA != Symbol::Flag::OmpShared)
2159
- makePrivateSymbol (dirContext.defaultDSA );
2145
+ declNewSymbol (dirContext.defaultDSA );
2160
2146
else
2161
- makeSharedSymbol ();
2147
+ useLastDeclSymbol ();
2162
2148
dsa = dirContext.defaultDSA ;
2163
2149
} else if (parallelDir) {
2164
2150
// 2) parallel -> shared
2165
- makeSharedSymbol ();
2151
+ useLastDeclSymbol ();
2166
2152
dsa = Symbol::Flag::OmpShared;
2167
2153
} else if (!taskGenDir && !targetDir) {
2168
2154
// 3) enclosing context
@@ -2175,12 +2161,12 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
2175
2161
// TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
2176
2162
if (prevDSA == Symbol::Flag::OmpShared) {
2177
2163
// 6) shared in enclosing context -> shared
2178
- makeSharedSymbol ();
2164
+ useLastDeclSymbol ();
2179
2165
dsa = Symbol::Flag::OmpShared;
2180
2166
} else {
2181
2167
// 7) firstprivate
2182
2168
dsa = Symbol::Flag::OmpFirstPrivate;
2183
- makePrivateSymbol (*dsa)->set (Symbol::Flag::OmpImplicit);
2169
+ declNewSymbol (*dsa)->set (Symbol::Flag::OmpImplicit);
2184
2170
}
2185
2171
}
2186
2172
prevDSA = dsa;
@@ -2584,59 +2570,20 @@ void ResolveOmpTopLevelParts(
2584
2570
});
2585
2571
}
2586
2572
2587
- static bool IsSymbolInCommonBlock (const Symbol &symbol) {
2588
- // TODO Improve the performance of this predicate function.
2589
- // Going through all symbols sequentially, in all common blocks, can be
2590
- // slow when there are many symbols. A possible optimization is to add
2591
- // an OmpInCommonBlock flag to Symbol, to make it possible to quickly
2592
- // test if a given symbol is in a common block.
2593
- for (const auto &cb : symbol.owner ().commonBlocks ()) {
2594
- if (IsCommonBlockContaining (cb.second .get (), symbol)) {
2595
- return true ;
2596
- }
2597
- }
2598
- return false ;
2599
- }
2600
-
2601
- static bool IsSymbolThreadprivate (const Symbol &symbol) {
2573
+ void OmpAttributeVisitor::CheckDataCopyingClause (
2574
+ const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
2575
+ const auto *checkSymbol{&symbol};
2602
2576
if (const auto *details{symbol.detailsIf <HostAssocDetails>()}) {
2603
- return details->symbol ().test (Symbol::Flag::OmpThreadprivate);
2604
- }
2605
- return symbol.test (Symbol::Flag::OmpThreadprivate);
2606
- }
2607
-
2608
- static bool IsSymbolPrivate (const Symbol &symbol) {
2609
- if (symbol.test (Symbol::Flag::OmpPrivate) ||
2610
- symbol.test (Symbol::Flag::OmpFirstPrivate)) {
2611
- return true ;
2612
- }
2613
- // A symbol that has not gone through constructs that may privatize the
2614
- // original symbol may be predetermined as private.
2615
- // (OMP 5.2 5.1.1 - Variables Referenced in a Construct)
2616
- if (symbol == symbol.GetUltimate ()) {
2617
- switch (symbol.owner ().kind ()) {
2618
- case Scope::Kind::MainProgram:
2619
- case Scope::Kind::Subprogram:
2620
- case Scope::Kind::BlockConstruct:
2621
- return !symbol.attrs ().test (Attr::SAVE) &&
2622
- !symbol.attrs ().test (Attr::PARAMETER) && !IsAssumedShape (symbol) &&
2623
- !IsSymbolInCommonBlock (symbol);
2624
- default :
2625
- return false ;
2626
- }
2577
+ checkSymbol = &details->symbol ();
2627
2578
}
2628
- return false ;
2629
- }
2630
2579
2631
- void OmpAttributeVisitor::CheckDataCopyingClause (
2632
- const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
2633
2580
if (ompFlag == Symbol::Flag::OmpCopyIn) {
2634
2581
// List of items/objects that can appear in a 'copyin' clause must be
2635
2582
// 'threadprivate'
2636
- if (!IsSymbolThreadprivate (symbol )) {
2583
+ if (!checkSymbol-> test (Symbol::Flag::OmpThreadprivate )) {
2637
2584
context_.Say (name.source ,
2638
2585
" Non-THREADPRIVATE object '%s' in COPYIN clause" _err_en_US,
2639
- symbol. name ());
2586
+ checkSymbol-> name ());
2640
2587
}
2641
2588
} else if (ompFlag == Symbol::Flag::OmpCopyPrivate &&
2642
2589
GetContext ().directive == llvm::omp::Directive::OMPD_single) {
@@ -2649,13 +2596,18 @@ void OmpAttributeVisitor::CheckDataCopyingClause(
2649
2596
" COPYPRIVATE variable '%s' may not appear on a PRIVATE or "
2650
2597
" FIRSTPRIVATE clause on a SINGLE construct" _err_en_US,
2651
2598
symbol.name ());
2652
- } else if (! IsSymbolThreadprivate (symbol) && ! IsSymbolPrivate (symbol)) {
2599
+ } else {
2653
2600
// List of items/objects that can appear in a 'copyprivate' clause must be
2654
2601
// either 'private' or 'threadprivate' in enclosing context.
2655
- context_.Say (name.source ,
2656
- " COPYPRIVATE variable '%s' is not PRIVATE or THREADPRIVATE in "
2657
- " outer context" _err_en_US,
2658
- symbol.name ());
2602
+ if (!checkSymbol->test (Symbol::Flag::OmpThreadprivate) &&
2603
+ !(HasSymbolInEnclosingScope (symbol, currScope ()) &&
2604
+ (symbol.test (Symbol::Flag::OmpPrivate) ||
2605
+ symbol.test (Symbol::Flag::OmpFirstPrivate)))) {
2606
+ context_.Say (name.source ,
2607
+ " COPYPRIVATE variable '%s' is not PRIVATE or THREADPRIVATE in "
2608
+ " outer context" _err_en_US,
2609
+ symbol.name ());
2610
+ }
2659
2611
}
2660
2612
}
2661
2613
}
@@ -2725,6 +2677,12 @@ void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source,
2725
2677
}
2726
2678
}
2727
2679
2680
+ bool OmpAttributeVisitor::HasSymbolInEnclosingScope (
2681
+ const Symbol &symbol, Scope &scope) {
2682
+ const auto symbols{scope.parent ().GetSymbols ()};
2683
+ return llvm::is_contained (symbols, symbol);
2684
+ }
2685
+
2728
2686
// Goes through the names in an OmpObjectList and checks if each name appears
2729
2687
// in the given allocate statement
2730
2688
void OmpAttributeVisitor::CheckAllNamesInAllocateStmt (
0 commit comments