40 ''' This module contains the PSyLoop node implementation.'''
48 '''Node representing a psylayer loop within the PSyIR. It extends the PSyIR
49 loop construct with information about the domain-specific iteration space
50 that the loop is traversing and utility methods to interact with other
53 :param List[str] valid_loop_types: a list of loop types that are specific \
55 :param kwargs: additional keyword arguments provided to the PSyIR node.
56 :type kwargs: unwrapped dict.
63 def __init__(self, valid_loop_types=None, **kwargs):
64 super().__init__(**kwargs)
66 if valid_loop_types
is None:
75 self.
_kern_kern =
None
84 Checks whether two nodes are equal. Two PSyLoop nodes are equal
85 if they have equal loop_type, field, field_name, field_space
86 iteraction_space and kernel.
88 :param object other: the object to check equality to.
90 :returns: whether other is equal to self.
93 is_eq = super().
__eq__(other)
95 is_eq = is_eq
and self.
fieldfieldfield == other.field
101 is_eq = is_eq
and self.
_iterates_over_iterates_over == other._iterates_over
108 :returns: the dag name to use for this loop.
113 _, position = self._find_position(self.ancestor(Routine))
114 name = f
"loop_[{self.loop_type}]_{position}"
116 name = super().dag_name
122 :returns: the (domain-specific) loop types allowed by this instance.
130 :returns: the (domain-specific) type of this loop.
136 def loop_type(self, value):
138 Set the type of this Loop.
140 :param str value: the type of this loop.
142 :raises TypeError: if the specified value is not a recognised \
147 f
"Error, loop_type value ({value}) is invalid. Must be one of "
148 f
"{self._valid_loop_types}.")
153 Returns the name of this node with (optional) control codes
154 to generate coloured output in a terminal that supports it.
156 :param bool colour: whether or not to include colour control codes.
158 :returns: description of this node, possibly coloured.
162 return (f
"{self.coloured_name(colour)}[type='{self._loop_type}', "
163 f
"field_space='{self._field_space}', "
164 f
"it_space='{self.iteration_space}']")
171 def field_space(self):
173 :returns: the field_space associated this loop.
179 def field_space(self, my_field_space):
180 ''' Set a new field_space for this loop.
182 :param my_field_space: the new field_space value.
183 :rtype my_field_space: str
188 def field_name(self):
190 :returns: the field name associated to this loop.
198 :returns: the field associated to this loop.
199 :rtype: :py:class:`psyclone.psyGen.Argument`
204 def field_name(self, my_field_name):
205 ''' Set a new field_name for the field associated to this loop.
207 :param str my_field_name: the new field name.
212 def iteration_space(self):
214 :returns: the iteration_space of this loop.
219 @iteration_space.setter
220 def iteration_space(self, it_space):
221 ''' Set a new iteration space for this loop.
223 :param str it_space: the new iteration_space fore this loop.
230 :returns: the kernel object associated with this PSyLoop (if any).
231 :rtype: Optional[:py:class:`psyclone.psyGen.Kern`]
233 return self.
_kern_kern
236 def kernel(self, kern):
238 Setter for kernel object associated with this PSyLoop.
240 :param kern: a kernel object.
241 :type kern: :py:class:`psyclone.psyGen.Kern`
243 self.
_kern_kern = kern
247 name = self.__class__.__name__
249 result +=
"variable:'" + self.variable.name
251 result +=
"', loop_type:'" + self.
_loop_type_loop_type
253 for entity
in self._children:
254 result += str(entity) +
"\n"
255 result +=
"End " + name
260 :returns: True if any of the Kernels called within this loop have an \
261 argument with INC access, False otherwise.
264 for kern_call
in self.coded_kernels():
265 for arg
in kern_call.arguments.args:
266 if arg.access == AccessType.INC:
271 '''Return all unique arguments of the given type from kernels inside
272 this loop that are modified.
274 :param str arg_type: the type of kernel argument (e.g. field, \
275 operator) to search for.
276 :returns: all unique arguments of the given type from kernels inside \
277 this loop that are modified.
278 :rtype: List[:py:class:`psyclone.psyGen.DynKernelArgument`]
282 for call
in self.kernels():
283 for arg
in call.arguments.args:
284 if arg.argument_type.lower() == arg_type:
285 if arg.access != AccessType.READ:
286 if arg.name
not in arg_names:
287 arg_names.append(arg.name)
293 :returns: fields in this loop that require at least some of their \
294 halo to be clean to work correctly.
295 :rtype: List[:py:class:`psyclone.psyGen.Argument`]
299 unique_field_names = []
301 for call
in self.kernels():
302 for arg
in call.arguments.args:
304 if arg.name
not in unique_field_names:
305 unique_field_names.append(arg.name)
306 unique_fields.append(arg)
309 def args_filter(self, arg_types=None, arg_accesses=None, unique=False):
311 :returns: all arguments of type arg_types and arg_accesses. If these \
312 are not set then return all arguments. If unique is set to \
313 True then only return uniquely named arguments.
314 :rtype: List[:py:class:`psyclone.psyGen.Argument`]
321 for call
in self.kernels():
322 call_args =
args_filter(call.arguments.args, arg_types,
325 for arg
in call_args:
326 if arg.name
not in all_arg_names:
328 all_arg_names.append(arg.name)
330 all_args.extend(call_args)
335 Generates the necessary code to mark halo regions as clean or dirty
336 following execution of this loop. This default implementation does
339 TODO #1648 - this method should be removed when the corresponding
340 one in LFRicLoop is removed.
342 :param parent: the node in the f2pygen AST to which to add content.
343 :type parent: :py:class:`psyclone.f2pygen.BaseGen`
347 def _halo_read_access(self, arg):
348 '''Determines whether the supplied argument has (or might have) its
349 halo data read within this loop. Returns True if it does, or if
350 it might and False if it definitely does not.
352 :param arg: an argument contained within this loop.
353 :type arg: :py:class:`psyclone.psyGen.KernelArgument`
355 :return: True if the argument reads, or might read from the \
356 halo and False otherwise.
359 :raises NotImplementedError: This is an abstract method.
362 raise NotImplementedError(
"This method needs to be implemented by the "
363 "APIs that support distributed memory.")
def iteration_space(self)
def loop_type(self, value)
def node_str(self, colour=True)
def args_filter(self, arg_types=None, arg_accesses=None, unique=False)
def unique_modified_args(self, arg_type)
def field_space(self, my_field_space)
def valid_loop_types(self)
def _halo_read_access(self, arg)
def unique_fields_with_halo_reads(self)
def gen_mark_halos_clean_dirty(self, parent)
def iteration_space(self, it_space)
def field_name(self, my_field_name)