4444from psyclone .psyir .nodes .loop import Loop
4545from psyclone .psyir .nodes .while_loop import WhileLoop
4646from psyclone .psyir .nodes .omp_clauses import OMPReductionClause
47+ from psyclone .psyir .nodes .reference import Reference
4748from psyclone .psyir .symbols import DataSymbol , Symbol
4849
4950
@@ -134,26 +135,42 @@ def infer_sharing_attributes(self) -> \
134135 continue
135136 symbol = accesses [0 ].node .scope .symbol_table .lookup (
136137 name , otherwise = None )
138+ if symbol is None :
139+ # The signature does not match any symbol! This is probably a
140+ # structure, we will consider them shared
141+ continue
142+
143+ # A parallel loop variable is always private
144+ if (isinstance (self .dir_body [0 ], Loop ) and
145+ self .dir_body [0 ].variable is symbol ):
146+ private .add (symbol )
147+ continue
137148
138149 # If it is manually marked as a local symbol, add it to private or
139150 # firstprivate set
140151 if (isinstance (symbol , DataSymbol ) and
141152 isinstance (self .dir_body [0 ], Loop ) and
142153 symbol in self .dir_body [0 ].explicitly_private_symbols ):
143154 visited = set ()
144- if (
145- # The loop variable is always private
146- self .dir_body [0 ].variable is not symbol and
147- # For anything else, if it uses a value coming from before
148- # the loop scope, make it firstprivate
149- any (access .node .enters_scope (self , visited_nodes = visited )
150- for access in accesses )):
151- fprivate .add (symbol )
155+ for access in accesses :
156+ if not isinstance (access .node , Reference ):
157+ # Nodes that are not References do not have
158+ # 'enters_scope', so the analysis below can't be
159+ # done and we defensively use 'firstprivate'
160+ # TODO #3124: Remove this special-case
161+ fprivate .add (symbol )
162+ break
163+ if access .node .enters_scope (self , visited ):
164+ # If it uses a value coming from before the loop
165+ # scope, make it 'firstprivate'
166+ fprivate .add (symbol )
167+ break
152168 else :
169+ # Everything else can be just 'private'
153170 private .add (symbol )
154171 continue
155172
156- # All arrays not explicitly marked as threadprivate are shared
173+ # All arrays not explicitly marked as explicitly_private are shared
157174 if any (accs .has_indices () for accs in accesses ):
158175 continue
159176
@@ -177,6 +194,7 @@ def infer_sharing_attributes(self) -> \
177194
178195 has_been_read = False
179196 last_read_position = 0
197+ visited_nodes = set () # To avoid enters_scope repetitions
180198 for access in accesses :
181199 if access .is_any_read ():
182200 has_been_read = True
@@ -195,19 +213,13 @@ def infer_sharing_attributes(self) -> \
195213 limit = self ,
196214 include_self = True )
197215 if not loop_ancestor :
198- # If we find it at least once outside a loop we keep it
199- # as shared
216+ # If we find it at least one WRITE outside a loop we
217+ # keep it as shared
200218 break
201219
202220 # Otherwise, the assignment to this variable is inside a
203221 # loop (and it will be repeated for each iteration), so
204- # we declare it as private or need_sync
205- name = signature .var_name
206- # TODO #2094: var_name only captures the top-level
207- # component in the derived type accessor. If the attributes
208- # only apply to a sub-component, this won't be captured
209- # appropriately.
210- symbol = access .node .scope .symbol_table .lookup (name )
222+ # we declare it as [first]private or need_sync
211223
212224 # If it has been read before we have to check if ...
213225 if has_been_read :
@@ -220,23 +232,31 @@ def infer_sharing_attributes(self) -> \
220232 need_sync .add (symbol )
221233 break
222234
223- # If the write is not guaranteed, we make it firstprivate
224- # so that in the case that the write doesn't happen we keep
225- # the original value
235+ # If the write is not guaranteed (because it is inside a
236+ # conditional), make it firstprivate to keep the original
237+ # value when the branch is never taken. Unless this never
238+ # had a value before the loop (as some compilers don't
239+ # like uninitialised firstprivates)
226240 conditional_write = access .node .ancestor (
227241 IfBlock ,
228242 limit = loop_ancestor ,
229243 include_self = True )
230244 if conditional_write :
231- # If it's used before the loop, make it firstprivate
232- visited = set ()
233- if any (access .node .enters_scope (
234- self , visited_nodes = visited )
235- for access in accesses ):
236- fprivate .add (symbol )
237- break
238- # Otherwise it is just private
239- private .add (symbol )
245+ # Check if it gets a value from before the loop
246+ for access in accesses :
247+ if not isinstance (access .node , Reference ):
248+ # Nodes that are not References do not have
249+ # 'enters_scope', so the analysis below can't
250+ # be done and we defensively use 'firstprivate'
251+ # TODO #3124: Remove this special-case
252+ fprivate .add (symbol )
253+ break
254+ if access .node .enters_scope (self , visited_nodes ):
255+ fprivate .add (symbol )
256+ break
257+ # Otherwise it is just 'private'
258+ if symbol not in fprivate :
259+ private .add (symbol )
240260 break
241261
242262 return private , fprivate , need_sync
0 commit comments