@@ -91,11 +91,12 @@ template <typename T> class DirectiveAttributeVisitor {
91
91
void SetContextAssociatedLoopLevel (std::int64_t level) {
92
92
GetContext ().associatedLoopLevel = level;
93
93
}
94
- Symbol &MakeAssocSymbol (const SourceName &name, Symbol &prev, Scope &scope) {
94
+ Symbol &MakeAssocSymbol (
95
+ const SourceName &name, const Symbol &prev, Scope &scope) {
95
96
const auto pair{scope.try_emplace (name, Attrs{}, HostAssocDetails{prev})};
96
97
return *pair.first ->second ;
97
98
}
98
- Symbol &MakeAssocSymbol (const SourceName &name, Symbol &prev) {
99
+ Symbol &MakeAssocSymbol (const SourceName &name, const Symbol &prev) {
99
100
return MakeAssocSymbol (name, prev, currScope ());
100
101
}
101
102
void AddDataSharingAttributeObject (SymbolRef object) {
@@ -108,6 +109,7 @@ template <typename T> class DirectiveAttributeVisitor {
108
109
const parser::Name *GetLoopIndex (const parser::DoConstruct &);
109
110
const parser::DoConstruct *GetDoConstructIf (
110
111
const parser::ExecutionPartConstruct &);
112
+ Symbol *DeclareNewPrivateAccessEntity (const Symbol &, Symbol::Flag, Scope &);
111
113
Symbol *DeclarePrivateAccessEntity (
112
114
const parser::Name &, Symbol::Flag, Scope &);
113
115
Symbol *DeclarePrivateAccessEntity (Symbol &, Symbol::Flag, Scope &);
@@ -736,6 +738,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
736
738
std::optional<common::OmpAtomicDefaultMemOrderType>);
737
739
void IssueNonConformanceWarning (
738
740
llvm::omp::Directive D, parser::CharBlock source);
741
+
742
+ void CreateImplicitSymbols (
743
+ const Symbol *symbol, std::optional<Symbol::Flag> setFlag = std::nullopt);
739
744
};
740
745
741
746
template <typename T>
@@ -771,6 +776,19 @@ const parser::DoConstruct *DirectiveAttributeVisitor<T>::GetDoConstructIf(
771
776
return parser::Unwrap<parser::DoConstruct>(x);
772
777
}
773
778
779
+ template <typename T>
780
+ Symbol *DirectiveAttributeVisitor<T>::DeclareNewPrivateAccessEntity(
781
+ const Symbol &object, Symbol::Flag flag, Scope &scope) {
782
+ assert (object.owner () != currScope ());
783
+ auto &symbol{MakeAssocSymbol (object.name (), object, scope)};
784
+ symbol.set (flag);
785
+ if (flag == Symbol::Flag::OmpCopyIn) {
786
+ // The symbol in copyin clause must be threadprivate entity.
787
+ symbol.set (Symbol::Flag::OmpThreadprivate);
788
+ }
789
+ return &symbol;
790
+ }
791
+
774
792
template <typename T>
775
793
Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity(
776
794
const parser::Name &name, Symbol::Flag flag, Scope &scope) {
@@ -785,13 +803,7 @@ template <typename T>
785
803
Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity(
786
804
Symbol &object, Symbol::Flag flag, Scope &scope) {
787
805
if (object.owner () != currScope ()) {
788
- auto &symbol{MakeAssocSymbol (object.name (), object, scope)};
789
- symbol.set (flag);
790
- if (flag == Symbol::Flag::OmpCopyIn) {
791
- // The symbol in copyin clause must be threadprivate entity.
792
- symbol.set (Symbol::Flag::OmpThreadprivate);
793
- }
794
- return &symbol;
806
+ return DeclareNewPrivateAccessEntity (object, flag, scope);
795
807
} else {
796
808
object.set (flag);
797
809
return &object;
@@ -2031,24 +2043,152 @@ void OmpAttributeVisitor::Post(const parser::OpenMPAllocatorsConstruct &x) {
2031
2043
PopContext ();
2032
2044
}
2033
2045
2046
+ static bool IsPrivatizable (const Symbol *sym) {
2047
+ auto *misc{sym->detailsIf <MiscDetails>()};
2048
+ return !IsProcedure (*sym) && !IsNamedConstant (*sym) &&
2049
+ !sym->owner ().IsDerivedType () &&
2050
+ sym->owner ().kind () != Scope::Kind::ImpliedDos &&
2051
+ !sym->detailsIf <semantics::AssocEntityDetails>() &&
2052
+ !sym->detailsIf <semantics::NamelistDetails>() &&
2053
+ (!misc ||
2054
+ (misc->kind () != MiscDetails::Kind::ComplexPartRe &&
2055
+ misc->kind () != MiscDetails::Kind::ComplexPartIm &&
2056
+ misc->kind () != MiscDetails::Kind::KindParamInquiry &&
2057
+ misc->kind () != MiscDetails::Kind::LenParamInquiry &&
2058
+ misc->kind () != MiscDetails::Kind::ConstructName));
2059
+ }
2060
+
2061
+ void OmpAttributeVisitor::CreateImplicitSymbols (
2062
+ const Symbol *symbol, std::optional<Symbol::Flag> setFlag) {
2063
+ if (!IsPrivatizable (symbol)) {
2064
+ return ;
2065
+ }
2066
+
2067
+ // Implicitly determined DSAs
2068
+ // OMP 5.2 5.1.1 - Variables Referenced in a Construct
2069
+ Symbol *lastDeclSymbol = nullptr ;
2070
+ std::optional<Symbol::Flag> prevDSA;
2071
+ for (int dirDepth{0 }; dirDepth < (int )dirContext_.size (); ++dirDepth) {
2072
+ DirContext &dirContext = dirContext_[dirDepth];
2073
+ std::optional<Symbol::Flag> dsa;
2074
+
2075
+ for (auto symMap : dirContext.objectWithDSA ) {
2076
+ // if the `symbol` already has a data-sharing attribute
2077
+ if (symMap.first ->name () == symbol->name ()) {
2078
+ dsa = symMap.second ;
2079
+ break ;
2080
+ }
2081
+ }
2082
+
2083
+ // When handling each implicit rule for a given symbol, one of the
2084
+ // following 3 actions may be taken:
2085
+ // 1. Declare a new private symbol.
2086
+ // 2. Create a new association symbol with no flags, that will represent
2087
+ // a shared symbol in the current scope. Note that symbols without
2088
+ // any private flags are considered as shared.
2089
+ // 3. Use the last declared private symbol, by inserting a new symbol
2090
+ // in the scope being processed, associated with it.
2091
+ // If no private symbol was declared previously, then no association
2092
+ // is needed and the symbol from the enclosing scope will be
2093
+ // inherited by the current one.
2094
+ //
2095
+ // Because of how symbols are collected in lowering, not inserting a new
2096
+ // symbol in the last case could lead to the conclusion that a symbol
2097
+ // from an enclosing construct was declared in the current construct,
2098
+ // which would result in wrong privatization code being generated.
2099
+ // Consider the following example:
2100
+ //
2101
+ // !$omp parallel default(private) ! p1
2102
+ // !$omp parallel default(private) shared(x) ! p2
2103
+ // x = 10
2104
+ // !$omp end parallel
2105
+ // !$omp end parallel
2106
+ //
2107
+ // If a new x symbol was not inserted in the inner parallel construct
2108
+ // (p2), it would use the x symbol definition from the enclosing scope.
2109
+ // Then, when p2's default symbols were collected in lowering, the x
2110
+ // symbol from the outer parallel construct (p1) would be collected, as
2111
+ // it would have the private flag set.
2112
+ // This would make x appear to be defined in p2, causing it to be
2113
+ // privatized in p2 and its privatization in p1 to be skipped.
2114
+ auto makePrivateSymbol = [&](Symbol::Flag flag) {
2115
+ const Symbol *hostSymbol =
2116
+ lastDeclSymbol ? lastDeclSymbol : &symbol->GetUltimate ();
2117
+ lastDeclSymbol = DeclareNewPrivateAccessEntity (
2118
+ *hostSymbol, flag, context_.FindScope (dirContext.directiveSource ));
2119
+ if (setFlag) {
2120
+ lastDeclSymbol->set (*setFlag);
2121
+ }
2122
+ return lastDeclSymbol;
2123
+ };
2124
+ auto makeSharedSymbol = [&]() {
2125
+ const Symbol *hostSymbol =
2126
+ lastDeclSymbol ? lastDeclSymbol : &symbol->GetUltimate ();
2127
+ MakeAssocSymbol (symbol->name (), *hostSymbol,
2128
+ context_.FindScope (dirContext.directiveSource ));
2129
+ };
2130
+ auto useLastDeclSymbol = [&]() {
2131
+ if (lastDeclSymbol) {
2132
+ makeSharedSymbol ();
2133
+ }
2134
+ };
2135
+
2136
+ bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
2137
+ bool targetDir = llvm::omp::allTargetSet.test (dirContext.directive );
2138
+ bool parallelDir = llvm::omp::allParallelSet.test (dirContext.directive );
2139
+ bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
2140
+
2141
+ if (dsa.has_value ()) {
2142
+ if (dsa.value () == Symbol::Flag::OmpShared &&
2143
+ (parallelDir || taskGenDir || teamsDir))
2144
+ makeSharedSymbol ();
2145
+ // Private symbols will have been declared already.
2146
+ prevDSA = dsa;
2147
+ continue ;
2148
+ }
2149
+
2150
+ if (dirContext.defaultDSA == Symbol::Flag::OmpPrivate ||
2151
+ dirContext.defaultDSA == Symbol::Flag::OmpFirstPrivate ||
2152
+ dirContext.defaultDSA == Symbol::Flag::OmpShared) {
2153
+ // 1) default
2154
+ // Allowed only with parallel, teams and task generating constructs.
2155
+ assert (parallelDir || taskGenDir || teamsDir);
2156
+ if (dirContext.defaultDSA != Symbol::Flag::OmpShared)
2157
+ makePrivateSymbol (dirContext.defaultDSA );
2158
+ else
2159
+ makeSharedSymbol ();
2160
+ dsa = dirContext.defaultDSA ;
2161
+ } else if (parallelDir) {
2162
+ // 2) parallel -> shared
2163
+ makeSharedSymbol ();
2164
+ dsa = Symbol::Flag::OmpShared;
2165
+ } else if (!taskGenDir && !targetDir) {
2166
+ // 3) enclosing context
2167
+ useLastDeclSymbol ();
2168
+ dsa = prevDSA;
2169
+ } else if (targetDir) {
2170
+ // TODO 4) not mapped target variable -> firstprivate
2171
+ dsa = prevDSA;
2172
+ } else if (taskGenDir) {
2173
+ // TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
2174
+ if (prevDSA == Symbol::Flag::OmpShared) {
2175
+ // 6) shared in enclosing context -> shared
2176
+ makeSharedSymbol ();
2177
+ dsa = Symbol::Flag::OmpShared;
2178
+ } else {
2179
+ // 7) firstprivate
2180
+ dsa = Symbol::Flag::OmpFirstPrivate;
2181
+ makePrivateSymbol (*dsa)->set (Symbol::Flag::OmpImplicit);
2182
+ }
2183
+ }
2184
+ prevDSA = dsa;
2185
+ }
2186
+ }
2187
+
2034
2188
// For OpenMP constructs, check all the data-refs within the constructs
2035
2189
// and adjust the symbol for each Name if necessary
2036
2190
void OmpAttributeVisitor::Post (const parser::Name &name) {
2037
2191
auto *symbol{name.symbol };
2038
- auto IsPrivatizable = [](const Symbol *sym) {
2039
- auto *misc{sym->detailsIf <MiscDetails>()};
2040
- return !IsProcedure (*sym) && !IsNamedConstant (*sym) &&
2041
- !sym->owner ().IsDerivedType () &&
2042
- sym->owner ().kind () != Scope::Kind::ImpliedDos &&
2043
- !sym->detailsIf <semantics::AssocEntityDetails>() &&
2044
- !sym->detailsIf <semantics::NamelistDetails>() &&
2045
- (!misc ||
2046
- (misc->kind () != MiscDetails::Kind::ComplexPartRe &&
2047
- misc->kind () != MiscDetails::Kind::ComplexPartIm &&
2048
- misc->kind () != MiscDetails::Kind::KindParamInquiry &&
2049
- misc->kind () != MiscDetails::Kind::LenParamInquiry &&
2050
- misc->kind () != MiscDetails::Kind::ConstructName));
2051
- };
2052
2192
2053
2193
if (symbol && !dirContext_.empty () && GetContext ().withinConstruct ) {
2054
2194
if (IsPrivatizable (symbol) && !IsObjectWithDSA (*symbol)) {
@@ -2076,125 +2216,20 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
2076
2216
if (found->test (semantics::Symbol::Flag::OmpThreadprivate))
2077
2217
return ;
2078
2218
}
2079
- if (!IsPrivatizable (symbol)) {
2080
- return ;
2081
- }
2082
-
2083
- // Implicitly determined DSAs
2084
- // OMP 5.2 5.1.1 - Variables Referenced in a Construct
2085
- Symbol *lastDeclSymbol = nullptr ;
2086
- std::optional<Symbol::Flag> prevDSA;
2087
- for (int dirDepth{0 }; dirDepth < (int )dirContext_.size (); ++dirDepth) {
2088
- DirContext &dirContext = dirContext_[dirDepth];
2089
- std::optional<Symbol::Flag> dsa;
2090
2219
2091
- for (auto symMap : dirContext.objectWithDSA ) {
2092
- // if the `symbol` already has a data-sharing attribute
2093
- if (symMap.first ->name () == name.symbol ->name ()) {
2094
- dsa = symMap.second ;
2095
- break ;
2096
- }
2097
- }
2098
-
2099
- // When handling each implicit rule for a given symbol, one of the
2100
- // following 3 actions may be taken:
2101
- // 1. Declare a new private symbol.
2102
- // 2. Create a new association symbol with no flags, that will represent
2103
- // a shared symbol in the current scope. Note that symbols without
2104
- // any private flags are considered as shared.
2105
- // 3. Use the last declared private symbol, by inserting a new symbol
2106
- // in the scope being processed, associated with it.
2107
- // If no private symbol was declared previously, then no association
2108
- // is needed and the symbol from the enclosing scope will be
2109
- // inherited by the current one.
2110
- //
2111
- // Because of how symbols are collected in lowering, not inserting a new
2112
- // symbol in the last case could lead to the conclusion that a symbol
2113
- // from an enclosing construct was declared in the current construct,
2114
- // which would result in wrong privatization code being generated.
2115
- // Consider the following example:
2116
- //
2117
- // !$omp parallel default(private) ! p1
2118
- // !$omp parallel default(private) shared(x) ! p2
2119
- // x = 10
2120
- // !$omp end parallel
2121
- // !$omp end parallel
2122
- //
2123
- // If a new x symbol was not inserted in the inner parallel construct
2124
- // (p2), it would use the x symbol definition from the enclosing scope.
2125
- // Then, when p2's default symbols were collected in lowering, the x
2126
- // symbol from the outer parallel construct (p1) would be collected, as
2127
- // it would have the private flag set.
2128
- // This would make x appear to be defined in p2, causing it to be
2129
- // privatized in p2 and its privatization in p1 to be skipped.
2130
- auto makePrivateSymbol = [&](Symbol::Flag flag) {
2131
- Symbol *hostSymbol =
2132
- lastDeclSymbol ? lastDeclSymbol : &symbol->GetUltimate ();
2133
- lastDeclSymbol = DeclarePrivateAccessEntity (
2134
- *hostSymbol, flag, context_.FindScope (dirContext.directiveSource ));
2135
- return lastDeclSymbol;
2136
- };
2137
- auto makeSharedSymbol = [&]() {
2138
- Symbol *hostSymbol =
2139
- lastDeclSymbol ? lastDeclSymbol : &symbol->GetUltimate ();
2140
- MakeAssocSymbol (symbol->name (), *hostSymbol,
2141
- context_.FindScope (dirContext.directiveSource ));
2142
- };
2143
- auto useLastDeclSymbol = [&]() {
2144
- if (lastDeclSymbol)
2145
- MakeAssocSymbol (symbol->name (), *lastDeclSymbol,
2146
- context_.FindScope (dirContext.directiveSource ));
2147
- };
2148
-
2149
- bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
2150
- bool targetDir = llvm::omp::allTargetSet.test (dirContext.directive );
2151
- bool parallelDir = llvm::omp::allParallelSet.test (dirContext.directive );
2152
- bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
2153
-
2154
- if (dsa.has_value ()) {
2155
- if (dsa.value () == Symbol::Flag::OmpShared &&
2156
- (parallelDir || taskGenDir || teamsDir))
2157
- makeSharedSymbol ();
2158
- // Private symbols will have been declared already.
2159
- prevDSA = dsa;
2160
- continue ;
2161
- }
2162
-
2163
- if (dirContext.defaultDSA == Symbol::Flag::OmpPrivate ||
2164
- dirContext.defaultDSA == Symbol::Flag::OmpFirstPrivate ||
2165
- dirContext.defaultDSA == Symbol::Flag::OmpShared) {
2166
- // 1) default
2167
- // Allowed only with parallel, teams and task generating constructs.
2168
- assert (parallelDir || taskGenDir || teamsDir);
2169
- if (dirContext.defaultDSA != Symbol::Flag::OmpShared)
2170
- makePrivateSymbol (dirContext.defaultDSA );
2171
- else
2172
- makeSharedSymbol ();
2173
- dsa = dirContext.defaultDSA ;
2174
- } else if (parallelDir) {
2175
- // 2) parallel -> shared
2176
- makeSharedSymbol ();
2177
- dsa = Symbol::Flag::OmpShared;
2178
- } else if (!taskGenDir && !targetDir) {
2179
- // 3) enclosing context
2180
- useLastDeclSymbol ();
2181
- dsa = prevDSA;
2182
- } else if (targetDir) {
2183
- // TODO 4) not mapped target variable -> firstprivate
2184
- dsa = prevDSA;
2185
- } else if (taskGenDir) {
2186
- // TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
2187
- if (prevDSA == Symbol::Flag::OmpShared) {
2188
- // 6) shared in enclosing context -> shared
2189
- makeSharedSymbol ();
2190
- dsa = Symbol::Flag::OmpShared;
2191
- } else {
2192
- // 7) firstprivate
2193
- dsa = Symbol::Flag::OmpFirstPrivate;
2194
- makePrivateSymbol (*dsa)->set (Symbol::Flag::OmpImplicit);
2220
+ if (auto *stmtFunction{symbol->detailsIf <semantics::SubprogramDetails>()};
2221
+ stmtFunction && stmtFunction->stmtFunction ()) {
2222
+ // Each non-dummy argument from a statement function must be handled too,
2223
+ // as if it was explicitly referenced.
2224
+ semantics::UnorderedSymbolSet symbols{
2225
+ CollectSymbols (stmtFunction->stmtFunction ().value ())};
2226
+ for (const auto &sym : symbols) {
2227
+ if (!IsStmtFunctionDummy (sym) && !IsObjectWithDSA (*sym)) {
2228
+ CreateImplicitSymbols (&*sym, Symbol::Flag::OmpFromStmtFunction);
2195
2229
}
2196
2230
}
2197
- prevDSA = dsa;
2231
+ } else {
2232
+ CreateImplicitSymbols (symbol);
2198
2233
}
2199
2234
} // within OpenMP construct
2200
2235
}
0 commit comments