Reference Guide  2.5.0
psyclone.psyir.nodes.node.Node Class Reference
Inheritance diagram for psyclone.psyir.nodes.node.Node:

Public Member Functions

def __init__ (self, ast=None, children=None, parent=None, annotations=None)
 
def __eq__ (self, other)
 
def coloured_name (self, colour=True)
 
def node_str (self, colour=True)
 
def __str__ (self)
 
def ast (self)
 
def ast_end (self)
 
def ast (self, ast)
 
def ast_end (self, ast_end)
 
def annotations (self)
 
def dag (self, file_name='dag', file_format='svg')
 
def dag_gen (self, graph)
 
def dag_name (self)
 
def args (self)
 
def backward_dependence (self)
 
def forward_dependence (self)
 
def is_valid_location (self, new_node, position="before")
 
def depth (self)
 
def view (self, depth=0, colour=True, indent=" ", _index=None)
 
def addchild (self, child, index=None)
 
def children (self)
 
def children (self, my_children)
 
def parent (self)
 
def siblings (self)
 
def has_constructor_parent (self)
 
def position (self)
 
def abs_position (self)
 
def root (self)
 
def sameParent (self, node_2)
 
def walk (self, my_type, stop_type=None, depth=None)
 
def get_sibling_lists (self, my_type, stop_type=None)
 
def ancestor (self, my_type, excluding=None, include_self=False, limit=None, shared_with=None)
 
def kernels (self)
 
def following (self, routine=True)
 
def preceding (self, reverse=False, routine=True)
 
def immediately_precedes (self, node_2)
 
def immediately_follows (self, node_1)
 
def coded_kernels (self)
 
def loops (self)
 
def reductions (self, reprod=None)
 
def is_openmp_parallel (self)
 
def lower_to_language_level (self)
 
def reference_accesses (self, var_accesses)
 
def scope (self)
 
def replace_with (self, node, keep_name_in_context=True)
 
def pop_all_children (self)
 
def detach (self)
 
def copy (self)
 
def validate_global_constraints (self)
 
def debug_string (self)
 
def origin_string (self)
 
def update_signal (self)
 
def path_from (self, ancestor)
 

Public Attributes

 position
 

Static Public Attributes

int START_DEPTH = 0
 
int START_POSITION = 0
 
 valid_annotations = tuple()
 

Detailed Description

Base class for a PSyIR node.

:param ast: reference into the fparser2 AST corresponding to this node.
:type ast: sub-class of :py:class:`fparser.two.Fortran2003.Base`
:param children: the PSyIR nodes that are children of this node.
:type children: list of :py:class:`psyclone.psyir.nodes.Node`
:param parent: that parent of this node in the PSyIR tree.
:type parent: :py:class:`psyclone.psyir.nodes.Node`
:param annotations: Tags that provide additional information about \
    the node. The node should still be functionally correct when \
    ignoring these tags.
:type annotations: list of str

:raises TypeError: if a parent is supplied that is not an instance of Node.
:raises InternalError: if an invalid annotation tag is supplied.

Definition at line 339 of file node.py.

Member Function Documentation

◆ __eq__()

def psyclone.psyir.nodes.node.Node.__eq__ (   self,
  other 
)
Checks whether two nodes are equal. The basic implementation of this
checks whether the nodes are the same type, and whether all children
of the nodes are equal, and if so then
they are considered equal.

:param object other: the object to check equality to.

:returns: whether other is equal to self.
:rtype: bool

Reimplemented in psyclone.psyir.nodes.scoping_node.ScopingNode, psyclone.psyir.nodes.routine.Routine, psyclone.psyir.nodes.reference.Reference, psyclone.psyir.nodes.psy_data_node.PSyDataNode, psyclone.psyir.nodes.operation.Operation, psyclone.psyir.nodes.omp_directives.OMPLoopDirective, psyclone.psyir.nodes.omp_directives.OMPDoDirective, psyclone.psyir.nodes.omp_clauses.OMPDependClause, psyclone.psyir.nodes.omp_clauses.OMPScheduleClause, psyclone.psyir.nodes.member.Member, psyclone.psyir.nodes.loop.Loop, psyclone.psyir.nodes.literal.Literal, psyclone.psyir.nodes.extract_node.ExtractNode, psyclone.psyir.nodes.container.Container, psyclone.psyir.nodes.codeblock.CodeBlock, psyclone.psyir.nodes.call.Call, psyclone.psyir.nodes.acc_directives.ACCUpdateDirective, psyclone.psyir.nodes.acc_directives.ACCKernelsDirective, and psyclone.psyir.nodes.acc_directives.ACCLoopDirective.

Definition at line 410 of file node.py.

410  def __eq__(self, other):
411  '''
412  Checks whether two nodes are equal. The basic implementation of this
413  checks whether the nodes are the same type, and whether all children
414  of the nodes are equal, and if so then
415  they are considered equal.
416 
417  :param object other: the object to check equality to.
418 
419  :returns: whether other is equal to self.
420  :rtype: bool
421  '''
422  super().__eq__(other)
423  is_eq = type(self) is type(other)
424  is_eq = is_eq and (len(self.children) == len(other.children))
425  for index, child in enumerate(self.children):
426  is_eq = is_eq and child == other.children[index]
427 
428  return is_eq
429 

References psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, and psyclone.psyir.nodes.node.Node.children().

Here is the call graph for this function:

◆ abs_position()

def psyclone.psyir.nodes.node.Node.abs_position (   self)
Find a Node's absolute position in the tree (starting with 0 if
it is the root). Needs to be computed dynamically from the
starting position (0) as its position may change.

:returns: absolute position of a Node in the tree.
:rtype: int

:raises InternalError: if the absolute position cannot be found.

Definition at line 994 of file node.py.

994  def abs_position(self):
995  '''
996  Find a Node's absolute position in the tree (starting with 0 if
997  it is the root). Needs to be computed dynamically from the
998  starting position (0) as its position may change.
999 
1000  :returns: absolute position of a Node in the tree.
1001  :rtype: int
1002 
1003  :raises InternalError: if the absolute position cannot be found.
1004 
1005  '''
1006  if self.root is self:
1007  return self.START_POSITION
1008  found, position = self._find_position(self.root.children,
1009  self.START_POSITION)
1010  if not found:
1011  raise InternalError("Error in search for Node position "
1012  "in the tree")
1013  return position
1014 

References psyclone.psyir.nodes.node.Node._find_position(), psyclone.f2pygen.BaseGen.root(), psyclone.f2pygen.BaseDeclGen.root(), psyclone.psyir.nodes.node.Node.root(), and psyclone.psyir.nodes.node.Node.START_POSITION.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ addchild()

def psyclone.psyir.nodes.node.Node.addchild (   self,
  child,
  index = None 
)
Adds the supplied node as a child of this node (at position index if
supplied). The supplied node must not have an existing parent.

:param child: the node to add as a child of this one.
:type child: :py:class:`psyclone.psyir.nodes.Node`
:param index: optional position at which to insert new child. Default \
              is to append new child to the list of existing children.
:type index: Optional[int]

Definition at line 909 of file node.py.

909  def addchild(self, child, index=None):
910  '''
911  Adds the supplied node as a child of this node (at position index if
912  supplied). The supplied node must not have an existing parent.
913 
914  :param child: the node to add as a child of this one.
915  :type child: :py:class:`psyclone.psyir.nodes.Node`
916  :param index: optional position at which to insert new child. Default \
917  is to append new child to the list of existing children.
918  :type index: Optional[int]
919 
920  '''
921  if index is not None:
922  self._children.insert(index, child)
923  else:
924  self._children.append(child)
925 

References psyclone.f2pygen.BaseGen._children, psyclone.psyir.nodes.node.Node._children, and psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children.

Here is the caller graph for this function:

◆ ancestor()

def psyclone.psyir.nodes.node.Node.ancestor (   self,
  my_type,
  excluding = None,
  include_self = False,
  limit = None,
  shared_with = None 
)
Search back up the tree and check whether this node has an ancestor
that is an instance of the supplied type. If it does then we return
it otherwise we return None. An individual (or tuple of) (sub-)
class(es) to ignore may be provided via the `excluding` argument. If
`include_self` is True then the current node is included in the search.
If `limit` is provided then the search ceases if/when the supplied
node is encountered.
If `shared_with` is provided, then the ancestor search will find an
ancestor of both this node and the node provided as `shared_with` if
such an ancestor exists.

:param my_type: class(es) to search for.
:type my_type: type | Tuple[type, ...]
:param excluding: (sub-)class(es) to ignore or None.
:type excluding: Optional[type | Tuple[type, ...]]
:param bool include_self: whether or not to include this node in the \
                          search.
:param limit: an optional node at which to stop the search.
:type limit: Optional[:py:class:`psyclone.psyir.nodes.Node`]
:param shared_with: an optional node which must also have the
                    found node as an ancestor.
:type shared_with: Optional[:py:class:`psyclone.psyir.nodes.Node`]

:returns: First ancestor Node that is an instance of any of the \
          requested classes or None if not found.
:rtype: Optional[:py:class:`psyclone.psyir.nodes.Node`]

:raises TypeError: if `excluding` is provided but is not a type or \
                   tuple of types.
:raises TypeError: if `limit` is provided but is not an instance \
                   of Node.

Definition at line 1160 of file node.py.

1161  limit=None, shared_with=None):
1162  '''
1163  Search back up the tree and check whether this node has an ancestor
1164  that is an instance of the supplied type. If it does then we return
1165  it otherwise we return None. An individual (or tuple of) (sub-)
1166  class(es) to ignore may be provided via the `excluding` argument. If
1167  `include_self` is True then the current node is included in the search.
1168  If `limit` is provided then the search ceases if/when the supplied
1169  node is encountered.
1170  If `shared_with` is provided, then the ancestor search will find an
1171  ancestor of both this node and the node provided as `shared_with` if
1172  such an ancestor exists.
1173 
1174  :param my_type: class(es) to search for.
1175  :type my_type: type | Tuple[type, ...]
1176  :param excluding: (sub-)class(es) to ignore or None.
1177  :type excluding: Optional[type | Tuple[type, ...]]
1178  :param bool include_self: whether or not to include this node in the \
1179  search.
1180  :param limit: an optional node at which to stop the search.
1181  :type limit: Optional[:py:class:`psyclone.psyir.nodes.Node`]
1182  :param shared_with: an optional node which must also have the
1183  found node as an ancestor.
1184  :type shared_with: Optional[:py:class:`psyclone.psyir.nodes.Node`]
1185 
1186  :returns: First ancestor Node that is an instance of any of the \
1187  requested classes or None if not found.
1188  :rtype: Optional[:py:class:`psyclone.psyir.nodes.Node`]
1189 
1190  :raises TypeError: if `excluding` is provided but is not a type or \
1191  tuple of types.
1192  :raises TypeError: if `limit` is provided but is not an instance \
1193  of Node.
1194  '''
1195  if include_self:
1196  myparent = self
1197  else:
1198  myparent = self.parent
1199 
1200  if excluding is not None:
1201  if isinstance(excluding, type):
1202  excludes = (excluding, )
1203  elif isinstance(excluding, tuple):
1204  excludes = excluding
1205  else:
1206  raise TypeError(
1207  f"The 'excluding' argument to ancestor() must be a type or"
1208  f" a tuple of types but got: '{type(excluding).__name__}'")
1209 
1210  if limit and not isinstance(limit, Node):
1211  raise TypeError(
1212  f"The 'limit' argument to ancestor() must be an instance of "
1213  f"Node but got '{type(limit).__name__}'")
1214 
1215  # If we need to find a shared ancestor, then find a starting ancestor
1216  # for the sharing node.
1217  shared_ancestor = None
1218  if shared_with is not None:
1219  shared_ancestor = shared_with.ancestor(
1220  my_type, excluding=excluding,
1221  include_self=include_self, limit=limit)
1222 
1223  while myparent is not None:
1224  if isinstance(myparent, my_type):
1225  if not (excluding and isinstance(myparent, excludes)):
1226  # If this is a valid instance but not the same as for
1227  # the shared_with node, we do logic afterwards to continue
1228  # searching upwards, as we could be either higher or
1229  # lower than the shared_ancestor found previously.
1230  if shared_ancestor and shared_ancestor is not myparent:
1231  break
1232  # This parent node is not an instance of an excluded
1233  # sub-class so return it
1234  return myparent
1235  if myparent is limit:
1236  break
1237  myparent = myparent.parent
1238 
1239  # We search up the tree until we find an ancestor of the requested
1240  # type(s) shared by the shared_with node.
1241  while (myparent is not shared_ancestor and myparent and
1242  shared_ancestor):
1243  if myparent is limit:
1244  break
1245  if myparent.depth > shared_ancestor.depth:
1246  # If myparent is deeper in the tree than the current
1247  # potential shared ancestor, search upwards to find
1248  # the next valid ancestor of this node.
1249  myparent = myparent.ancestor(
1250  my_type, excluding=excluding,
1251  include_self=False, limit=limit)
1252  else:
1253  # shared_ancestor is equal or deeper in the tree than
1254  # myparent, so search upwards for the next valid ancestor
1255  # of shared_ancestor.
1256  shared_ancestor = shared_ancestor.ancestor(
1257  my_type, excluding=excluding, include_self=False,
1258  limit=limit)
1259  # If myparent is shared ancestor then return myparent.
1260  if myparent is shared_ancestor:
1261  return myparent
1262 
1263  # Otherwise we didn't find an ancestor that was valid.
1264  return None
1265 

References psyclone.f2pygen.BaseGen.parent(), and psyclone.psyir.nodes.node.Node.parent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ annotations()

def psyclone.psyir.nodes.node.Node.annotations (   self)
 Return the list of annotations attached to this Node.

:returns: List of anotations
:rtype: list of str

Definition at line 540 of file node.py.

540  def annotations(self):
541  ''' Return the list of annotations attached to this Node.
542 
543  :returns: List of anotations
544  :rtype: list of str
545  '''
546  return self._annotations
547 

References psyclone.psyir.nodes.node.Node._annotations.

Here is the caller graph for this function:

◆ args()

def psyclone.psyir.nodes.node.Node.args (   self)
Return the list of arguments associated with this Node. The default
implementation assumes the Node has no directly associated
arguments (i.e. is not a Kern class or subclass). Arguments of
any of this nodes descendants are considered to be
associated. 

Definition at line 679 of file node.py.

679  def args(self):
680  '''Return the list of arguments associated with this Node. The default
681  implementation assumes the Node has no directly associated
682  arguments (i.e. is not a Kern class or subclass). Arguments of
683  any of this nodes descendants are considered to be
684  associated. '''
685  args = []
686  for call in self.kernels():
687  args.extend(call.args)
688  return args
689 

References psyclone.psyir.nodes.node.Node.kernels().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ast() [1/2]

def psyclone.psyir.nodes.node.Node.ast (   self)
:returns: a reference to that part of the fparser2 parse tree that \
          this node represents or None.
:rtype: sub-class of :py:class:`fparser.two.utils.Base`

Definition at line 502 of file node.py.

502  def ast(self):
503  '''
504  :returns: a reference to that part of the fparser2 parse tree that \
505  this node represents or None.
506  :rtype: sub-class of :py:class:`fparser.two.utils.Base`
507  '''
508  return self._ast
509 

References psyclone.alg_gen.Alg._ast, psyclone.parse.kernel.KernelType._ast, and psyclone.psyir.nodes.node.Node._ast.

Here is the caller graph for this function:

◆ ast() [2/2]

def psyclone.psyir.nodes.node.Node.ast (   self,
  ast 
)
Set a reference to the fparser2 node associated with this Node.

:param ast: fparser2 node associated with this Node.
:type ast: :py:class:`fparser.two.utils.Base`

Definition at line 520 of file node.py.

520  def ast(self, ast):
521  '''
522  Set a reference to the fparser2 node associated with this Node.
523 
524  :param ast: fparser2 node associated with this Node.
525  :type ast: :py:class:`fparser.two.utils.Base`
526  '''
527  self._ast = ast
528 

References psyclone.alg_gen.Alg._ast, psyclone.parse.kernel.KernelType._ast, psyclone.psyir.nodes.node.Node._ast, and psyclone.psyir.nodes.node.Node.ast().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ast_end() [1/2]

def psyclone.psyir.nodes.node.Node.ast_end (   self)
:returns: a reference to the last node in the fparser2 parse tree \
          that represents a child of this PSyIR node or None.
:rtype: sub-class of :py:class:`fparser.two.utils.Base`

Definition at line 511 of file node.py.

511  def ast_end(self):
512  '''
513  :returns: a reference to the last node in the fparser2 parse tree \
514  that represents a child of this PSyIR node or None.
515  :rtype: sub-class of :py:class:`fparser.two.utils.Base`
516  '''
517  return self._ast_end
518 

References psyclone.psyir.nodes.node.Node._ast_end.

Here is the caller graph for this function:

◆ ast_end() [2/2]

def psyclone.psyir.nodes.node.Node.ast_end (   self,
  ast_end 
)
Set a reference to the last fparser2 node associated with this Node.

:param ast: last fparser2 node associated with this Node.
:type ast: :py:class:`fparser.two.utils.Base`

Definition at line 530 of file node.py.

530  def ast_end(self, ast_end):
531  '''
532  Set a reference to the last fparser2 node associated with this Node.
533 
534  :param ast: last fparser2 node associated with this Node.
535  :type ast: :py:class:`fparser.two.utils.Base`
536  '''
537  self._ast_end = ast_end
538 

References psyclone.psyir.nodes.node.Node._ast_end, and psyclone.psyir.nodes.node.Node.ast_end().

Here is the call graph for this function:

◆ backward_dependence()

def psyclone.psyir.nodes.node.Node.backward_dependence (   self)
Returns the closest preceding Node that this Node has a direct
dependence with or None if there is not one. Only Nodes with
the same parent as self are returned. Nodes inherit their
descendants' dependencies. The reason for this is that for
correctness a node must maintain its parent if it is
moved. For example a halo exchange and a kernel call may have
a dependence between them but it is the loop body containing
the kernel call that the halo exchange must not move beyond
i.e. the loop body inherits the dependencies of the routines
within it.

Definition at line 690 of file node.py.

690  def backward_dependence(self):
691  '''Returns the closest preceding Node that this Node has a direct
692  dependence with or None if there is not one. Only Nodes with
693  the same parent as self are returned. Nodes inherit their
694  descendants' dependencies. The reason for this is that for
695  correctness a node must maintain its parent if it is
696  moved. For example a halo exchange and a kernel call may have
697  a dependence between them but it is the loop body containing
698  the kernel call that the halo exchange must not move beyond
699  i.e. the loop body inherits the dependencies of the routines
700  within it.'''
701  dependence = None
702  # look through all the backward dependencies of my arguments
703  for arg in self.args:
704  dependent_arg = arg.backward_dependence()
705  if dependent_arg:
706  # this argument has a backward dependence
707  node = dependent_arg.call
708  # if the remote node is deeper in the tree than me
709  # then find the ancestor that is at the same level of
710  # the tree as me.
711  while node.depth > self.depth:
712  node = node.parent
713  if self.sameParent(node) and node is not self:
714  # The remote node (or one of its ancestors) shares
715  # the same parent as me (but its not me)
716  if not dependence:
717  # this is the first dependence found so keep it
718  dependence = node
719  else:
720  # we have already found a dependence
721  if dependence.position < node.position:
722  # the new dependence is closer to me than
723  # the previous dependence so keep it
724  dependence = node
725  return dependence
726 

References psyclone.expression.FunctionVar.args, psyclone.f2pygen.SubroutineGen.args(), psyclone.parse.algorithm.ParsedCall.args(), psyclone.psyGen.GlobalSum.args(), psyclone.psyGen.HaloExchange.args(), psyclone.psyGen.Kern.args(), psyclone.psyGen.Arguments.args(), psyclone.psyir.nodes.node.Node.args(), psyclone.psyir.nodes.node.Node.depth(), psyclone.gocean1p0.GOStencil.depth(), and psyclone.psyir.nodes.node.Node.sameParent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ children() [1/2]

def psyclone.psyir.nodes.node.Node.children (   self)
:returns: the immediate children of this Node.
:rtype: List[:py:class:`psyclone.psyir.nodes.Node`]

Definition at line 927 of file node.py.

927  def children(self):
928  '''
929  :returns: the immediate children of this Node.
930  :rtype: List[:py:class:`psyclone.psyir.nodes.Node`]
931  '''
932  return self._children
933 

References psyclone.f2pygen.BaseGen._children, psyclone.psyir.nodes.node.Node._children, and psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children.

Here is the caller graph for this function:

◆ children() [2/2]

def psyclone.psyir.nodes.node.Node.children (   self,
  my_children 
)
 Set a new children list.

:param my_children: new list of children.
:type my_children: list

:raises TypeError: if the given children parameter is not a list.

Definition at line 935 of file node.py.

935  def children(self, my_children):
936  ''' Set a new children list.
937 
938  :param my_children: new list of children.
939  :type my_children: list
940 
941  :raises TypeError: if the given children parameter is not a list.
942  '''
943  if isinstance(my_children, list):
944  self.pop_all_children() # First remove existing children if any
945  self._children = ChildrenList(self, self._validate_child,
946  self._children_valid_format)
947  self._children.extend(my_children)
948  else:
949  raise TypeError("The 'my_children' parameter of the node.children"
950  " setter must be a list.")
951 

References psyclone.f2pygen.BaseGen._children, psyclone.psyir.nodes.node.Node._children, psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._children_valid_format, psyclone.domain.common.algorithm.psyir.KernelFunctor._children_valid_format, psyclone.domain.lfric.algorithm.psyir.lfric_alg_invoke_call.LFRicAlgorithmInvokeCall._children_valid_format, psyclone.psyGen.GlobalSum._children_valid_format, psyclone.psyGen.HaloExchange._children_valid_format, psyclone.psyGen.Kern._children_valid_format, psyclone.psyGen.InlinedKern._children_valid_format, psyclone.psyir.nodes.acc_clauses.ACCCopyClause._children_valid_format, psyclone.psyir.nodes.acc_clauses.ACCCopyInClause._children_valid_format, psyclone.psyir.nodes.acc_clauses.ACCCopyOutClause._children_valid_format, psyclone.psyir.nodes.array_member.ArrayMember._children_valid_format, psyclone.psyir.nodes.array_of_structures_member.ArrayOfStructuresMember._children_valid_format, psyclone.psyir.nodes.array_of_structures_reference.ArrayOfStructuresReference._children_valid_format, psyclone.psyir.nodes.array_reference.ArrayReference._children_valid_format, psyclone.psyir.nodes.assignment.Assignment._children_valid_format, psyclone.psyir.nodes.call.Call._children_valid_format, psyclone.psyir.nodes.clause.Clause._children_valid_format, psyclone.psyir.nodes.codeblock.CodeBlock._children_valid_format, psyclone.psyir.nodes.container.Container._children_valid_format, psyclone.psyir.nodes.directive.RegionDirective._children_valid_format, psyclone.psyir.nodes.directive.StandaloneDirective._children_valid_format, psyclone.psyir.nodes.dynamic_omp_task_directive.DynamicOMPTaskDirective._children_valid_format, psyclone.psyir.nodes.if_block.IfBlock._children_valid_format, psyclone.psyir.nodes.intrinsic_call.IntrinsicCall._children_valid_format, psyclone.psyir.nodes.literal.Literal._children_valid_format, psyclone.psyir.nodes.loop.Loop._children_valid_format, psyclone.psyir.nodes.member.Member._children_valid_format, psyclone.psyir.nodes.node.Node._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPNowaitClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPGrainsizeClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPNumTasksClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPNogroupClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPSharedClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPPrivateClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPFirstprivateClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPDefaultClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPScheduleClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPDependClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPReductionClause._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPSingleDirective._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPTaskloopDirective._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPParallelDoDirective._children_valid_format, psyclone.psyir.nodes.omp_task_directive.OMPTaskDirective._children_valid_format, psyclone.psyir.nodes.operation.UnaryOperation._children_valid_format, psyclone.psyir.nodes.operation.BinaryOperation._children_valid_format, psyclone.psyir.nodes.psy_data_node.PSyDataNode._children_valid_format, psyclone.psyir.nodes.ranges.Range._children_valid_format, psyclone.psyir.nodes.reference.Reference._children_valid_format, psyclone.psyir.nodes.return_stmt.Return._children_valid_format, psyclone.psyir.nodes.routine.Routine._children_valid_format, psyclone.psyir.nodes.schedule.Schedule._children_valid_format, psyclone.psyir.nodes.structure_member.StructureMember._children_valid_format, psyclone.psyir.nodes.structure_reference.StructureReference._children_valid_format, psyclone.psyir.nodes.while_loop.WhileLoop._children_valid_format, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._validate_child(), psyclone.domain.common.algorithm.psyir.KernelFunctor._validate_child(), psyclone.domain.lfric.algorithm.psyir.lfric_alg_invoke_call.LFRicAlgorithmInvokeCall._validate_child(), psyclone.psyGen.InlinedKern._validate_child(), psyclone.psyir.nodes.acc_clauses.ACCCopyClause._validate_child(), psyclone.psyir.nodes.acc_clauses.ACCCopyInClause._validate_child(), psyclone.psyir.nodes.acc_clauses.ACCCopyOutClause._validate_child(), psyclone.psyir.nodes.acc_directives.ACCDataDirective._validate_child(), psyclone.psyir.nodes.array_mixin.ArrayMixin._validate_child(), psyclone.psyir.nodes.array_of_structures_mixin.ArrayOfStructuresMixin._validate_child(), psyclone.psyir.nodes.assignment.Assignment._validate_child(), psyclone.psyir.nodes.call.Call._validate_child(), psyclone.psyir.nodes.container.Container._validate_child(), psyclone.psyir.nodes.directive.RegionDirective._validate_child(), psyclone.psyir.nodes.directive.StandaloneDirective._validate_child(), psyclone.psyir.nodes.if_block.IfBlock._validate_child(), psyclone.psyir.nodes.loop.Loop._validate_child(), psyclone.psyir.nodes.node.Node._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPGrainsizeClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPNumTasksClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPSharedClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPPrivateClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPFirstprivateClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPDependClause._validate_child(), psyclone.psyir.nodes.omp_directives.OMPSingleDirective._validate_child(), psyclone.psyir.nodes.omp_directives.OMPParallelDirective._validate_child(), psyclone.psyir.nodes.omp_directives.OMPTaskloopDirective._validate_child(), psyclone.psyir.nodes.omp_directives.OMPParallelDoDirective._validate_child(), psyclone.psyir.nodes.omp_task_directive.OMPTaskDirective._validate_child(), psyclone.psyir.nodes.operation.UnaryOperation._validate_child(), psyclone.psyir.nodes.operation.BinaryOperation._validate_child(), psyclone.psyir.nodes.psy_data_node.PSyDataNode._validate_child(), psyclone.psyir.nodes.ranges.Range._validate_child(), psyclone.psyir.nodes.schedule.Schedule._validate_child(), psyclone.psyir.nodes.structure_member.StructureMember._validate_child(), psyclone.psyir.nodes.structure_reference.StructureReference._validate_child(), psyclone.psyir.nodes.while_loop.WhileLoop._validate_child(), psyclone.psyir.nodes.node.Node.children(), and psyclone.psyir.nodes.node.Node.pop_all_children().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ coded_kernels()

def psyclone.psyir.nodes.node.Node.coded_kernels (   self)
Returns a list of all of the user-supplied kernels (as opposed to
builtins) that are beneath this node in the PSyIR.

:returns: all user-supplied kernel calls below this node.
:rtype: List[:py:class:`psyclone.psyGen.CodedKern`]

Definition at line 1374 of file node.py.

1374  def coded_kernels(self):
1375  '''
1376  Returns a list of all of the user-supplied kernels (as opposed to
1377  builtins) that are beneath this node in the PSyIR.
1378 
1379  :returns: all user-supplied kernel calls below this node.
1380  :rtype: List[:py:class:`psyclone.psyGen.CodedKern`]
1381 
1382  '''
1383  # pylint: disable=import-outside-toplevel
1384  from psyclone.psyGen import CodedKern
1385  return self.walk(CodedKern)
1386 

References psyclone.psyir.nodes.node.Node.walk().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ coloured_name()

def psyclone.psyir.nodes.node.Node.coloured_name (   self,
  colour = True 
)
Returns the display name of this Node, optionally with colour control
codes (requires that the termcolor package be installed).

:param bool colour: whether or not to include colour control codes \
                    in the result.

:returns: the name of this node, optionally with colour control codes.
:rtype: str

Definition at line 453 of file node.py.

453  def coloured_name(self, colour=True):
454  '''
455  Returns the display name of this Node, optionally with colour control
456  codes (requires that the termcolor package be installed).
457 
458  :param bool colour: whether or not to include colour control codes \
459  in the result.
460 
461  :returns: the name of this node, optionally with colour control codes.
462  :rtype: str
463  '''
464  if not self._text_name:
465  name_string = type(self).__name__
466  else:
467  name_string = self._text_name
468  if colour:
469  if self._colour is None:
470  raise NotImplementedError(
471  f"The _colour attribute is abstract so needs to be given "
472  f"a string value in the concrete class "
473  f"'{type(self).__name__}'.")
474  try:
475  return colored(name_string, self._colour)
476  except KeyError as info:
477  raise InternalError(
478  f"The _colour attribute in class '{type(self).__name__}' "
479  f"has been set to a colour ('{self._colour}') that is not "
480  f"supported by the termcolor package.") from info
481  return name_string
482 

References psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._colour, psyclone.domain.common.psylayer.psyloop.PSyLoop._colour, psyclone.dynamo0p3.LFRicHaloExchangeStart._colour, psyclone.dynamo0p3.LFRicHaloExchangeEnd._colour, psyclone.psyGen.GlobalSum._colour, psyclone.psyGen.HaloExchange._colour, psyclone.psyGen.CodedKern._colour, psyclone.psyGen.InlinedKern._colour, psyclone.psyGen.BuiltIn._colour, psyclone.psyir.nodes.assignment.Assignment._colour, psyclone.psyir.nodes.call.Call._colour, psyclone.psyir.nodes.clause.Clause._colour, psyclone.psyir.nodes.codeblock.CodeBlock._colour, psyclone.psyir.nodes.container.Container._colour, psyclone.psyir.nodes.directive.Directive._colour, psyclone.psyir.nodes.extract_node.ExtractNode._colour, psyclone.psyir.nodes.file_container.FileContainer._colour, psyclone.psyir.nodes.if_block.IfBlock._colour, psyclone.psyir.nodes.intrinsic_call.IntrinsicCall._colour, psyclone.psyir.nodes.literal.Literal._colour, psyclone.psyir.nodes.loop.Loop._colour, psyclone.psyir.nodes.member.Member._colour, psyclone.psyir.nodes.nan_test_node.NanTestNode._colour, psyclone.psyir.nodes.node.Node._colour, psyclone.psyir.nodes.operation.Operation._colour, psyclone.psyir.nodes.profile_node.ProfileNode._colour, psyclone.psyir.nodes.psy_data_node.PSyDataNode._colour, psyclone.psyir.nodes.ranges.Range._colour, psyclone.psyir.nodes.read_only_verify_node.ReadOnlyVerifyNode._colour, psyclone.psyir.nodes.reference.Reference._colour, psyclone.psyir.nodes.return_stmt.Return._colour, psyclone.psyir.nodes.schedule.Schedule._colour, psyclone.psyir.nodes.while_loop.WhileLoop._colour, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._text_name, psyclone.domain.common.algorithm.psyir.KernelFunctor._text_name, psyclone.domain.common.psylayer.psyloop.PSyLoop._text_name, psyclone.domain.lfric.algorithm.psyir.lfric_alg_invoke_call.LFRicAlgorithmInvokeCall._text_name, psyclone.domain.lfric.algorithm.psyir.lfric_kernel_functor.LFRicFunctor._text_name, psyclone.domain.lfric.algorithm.psyir.lfric_kernel_functor.LFRicKernelFunctor._text_name, psyclone.domain.lfric.algorithm.psyir.lfric_kernel_functor.LFRicBuiltinFunctor._text_name, psyclone.dynamo0p3.LFRicHaloExchangeStart._text_name, psyclone.dynamo0p3.LFRicHaloExchangeEnd._text_name, psyclone.gocean1p0.GOInvokeSchedule._text_name, psyclone.nemo.NemoInvokeSchedule._text_name, psyclone.psyGen.InvokeSchedule._text_name, psyclone.psyGen.GlobalSum._text_name, psyclone.psyGen.HaloExchange._text_name, psyclone.psyGen.CodedKern._text_name, psyclone.psyGen.InlinedKern._text_name, psyclone.psyGen.BuiltIn._text_name, psyclone.psyir.nodes.array_member.ArrayMember._text_name, psyclone.psyir.nodes.array_of_structures_member.ArrayOfStructuresMember._text_name, psyclone.psyir.nodes.array_of_structures_reference.ArrayOfStructuresReference._text_name, psyclone.psyir.nodes.array_reference.ArrayReference._text_name, psyclone.psyir.nodes.assignment.Assignment._text_name, psyclone.psyir.nodes.call.Call._text_name, psyclone.psyir.nodes.codeblock.CodeBlock._text_name, psyclone.psyir.nodes.container.Container._text_name, psyclone.psyir.nodes.extract_node.ExtractNode._text_name, psyclone.psyir.nodes.file_container.FileContainer._text_name, psyclone.psyir.nodes.if_block.IfBlock._text_name, psyclone.psyir.nodes.intrinsic_call.IntrinsicCall._text_name, psyclone.psyir.nodes.kernel_schedule.KernelSchedule._text_name, psyclone.psyir.nodes.literal.Literal._text_name, psyclone.psyir.nodes.loop.Loop._text_name, psyclone.psyir.nodes.member.Member._text_name, psyclone.psyir.nodes.nan_test_node.NanTestNode._text_name, psyclone.psyir.nodes.node.Node._text_name, psyclone.psyir.nodes.omp_directives.OMPSingleDirective._text_name, psyclone.psyir.nodes.omp_directives.OMPMasterDirective._text_name, psyclone.psyir.nodes.profile_node.ProfileNode._text_name, psyclone.psyir.nodes.psy_data_node.PSyDataNode._text_name, psyclone.psyir.nodes.ranges.Range._text_name, psyclone.psyir.nodes.read_only_verify_node.ReadOnlyVerifyNode._text_name, psyclone.psyir.nodes.reference.Reference._text_name, psyclone.psyir.nodes.return_stmt.Return._text_name, psyclone.psyir.nodes.routine.Routine._text_name, psyclone.psyir.nodes.schedule.Schedule._text_name, psyclone.psyir.nodes.structure_member.StructureMember._text_name, and psyclone.psyir.nodes.structure_reference.StructureReference._text_name.

Here is the caller graph for this function:

◆ copy()

def psyclone.psyir.nodes.node.Node.copy (   self)
 Return a copy of this node. This is a bespoke implementation for
PSyIR nodes that will deepcopy some of its recursive data-structure
(e.g. the children tree), while not copying other attributes (e.g.
top-level parent reference).

:returns: a copy of this node and its children.
:rtype: :py:class:`psyclone.psyir.node.Node`

Reimplemented in psyclone.psyir.nodes.call.Call.

Definition at line 1588 of file node.py.

1588  def copy(self):
1589  ''' Return a copy of this node. This is a bespoke implementation for
1590  PSyIR nodes that will deepcopy some of its recursive data-structure
1591  (e.g. the children tree), while not copying other attributes (e.g.
1592  top-level parent reference).
1593 
1594  :returns: a copy of this node and its children.
1595  :rtype: :py:class:`psyclone.psyir.node.Node`
1596 
1597  '''
1598  # Start with a shallow copy of the object
1599  new_instance = copy.copy(self)
1600  # and then refine the elements that shouldn't be shallow copied
1601  # pylint: disable=protected-access
1602  new_instance._refine_copy(self)
1603  return new_instance
1604 

◆ dag()

def psyclone.psyir.nodes.node.Node.dag (   self,
  file_name = 'dag',
  file_format = 'svg' 
)
Create a dag of this node and its children, write it to file and
return the graph object.

:param str file_name: name of the file to create.
:param str file_format: format of the file to create. (Must be one \
                        recognised by Graphviz.)

:returns: the graph object or None (if the graphviz bindings are not \
          installed).
:rtype: :py:class:`graphviz.Digraph` or NoneType

:raises GenerationError: if the specified file format is not \
                         recognised by Graphviz.

Definition at line 548 of file node.py.

548  def dag(self, file_name='dag', file_format='svg'):
549  '''
550  Create a dag of this node and its children, write it to file and
551  return the graph object.
552 
553  :param str file_name: name of the file to create.
554  :param str file_format: format of the file to create. (Must be one \
555  recognised by Graphviz.)
556 
557  :returns: the graph object or None (if the graphviz bindings are not \
558  installed).
559  :rtype: :py:class:`graphviz.Digraph` or NoneType
560 
561  :raises GenerationError: if the specified file format is not \
562  recognised by Graphviz.
563 
564  '''
565  digraph = _graphviz_digraph_class()
566  if digraph is None:
567  return None
568  try:
569  graph = digraph(format=file_format)
570  except ValueError as err:
571  raise GenerationError(f"unsupported graphviz file format "
572  f"'{file_format}' provided") from err
573  self.dag_gen(graph)
574  graph.render(filename=file_name)
575  return graph
576 

References psyclone.psyir.nodes.node.Node.dag_gen().

Here is the call graph for this function:

◆ dag_gen()

def psyclone.psyir.nodes.node.Node.dag_gen (   self,
  graph 
)
Output my node's graph (dag) information and call any
children. Nodes with children are represented as two vertices,
a start and an end. Forward dependencies are represented as
green edges, backward dependencies are represented as red
edges (but their direction is reversed so the layout looks
reasonable) and parent child dependencies are represented as
blue edges.

Definition at line 577 of file node.py.

577  def dag_gen(self, graph):
578  '''Output my node's graph (dag) information and call any
579  children. Nodes with children are represented as two vertices,
580  a start and an end. Forward dependencies are represented as
581  green edges, backward dependencies are represented as red
582  edges (but their direction is reversed so the layout looks
583  reasonable) and parent child dependencies are represented as
584  blue edges.'''
585  # Import outside top-level to avoid circular dependencies.
586  # pylint: disable=too-many-branches, import-outside-toplevel
587  from psyclone.psyir.nodes.loop import Loop
588  from psyclone.psyir.nodes.routine import Routine
589 
590  # names to append to my default name to create start and end vertices
591  start_postfix = "_start"
592  end_postfix = "_end"
593  if self.children:
594  # I am represented by two vertices, a start and an end
595  graph.node(self.dag_name+start_postfix)
596  graph.node(self.dag_name+end_postfix)
597  else:
598  # I am represented by a single vertex
599  graph.node(self.dag_name)
600  # first deal with forward dependencies
601  remote_node = self.forward_dependence()
602  local_name = self.dag_name
603  if self.children:
604  # edge will come from my end vertex as I am a forward dependence
605  local_name += end_postfix
606  if remote_node:
607  # this node has a forward dependence
608  remote_name = remote_node.dag_name
609  if remote_node.children:
610  # the remote node has children so I will connect to
611  # its start vertex
612  remote_name += start_postfix
613  # Create the forward dependence edge in green
614  graph.edge(local_name, remote_name, color="green")
615  elif not isinstance(self, Routine):
616  # If this node is not a Routine (where the DAG context finishes)
617  # and has no forward dependence, connect it to the end vertex
618  # of its parent. Use blue to indicate a parent child
619  # relationship.
620  remote_name = self.parent.dag_name + end_postfix
621  graph.edge(local_name, remote_name, color="blue")
622  # now deal with backward dependencies. When creating the edges
623  # we reverse the direction of the dependence (place
624  # remote_node before local_node) to help with the graph
625  # layout
626  remote_node = self.backward_dependence()
627  local_name = self.dag_name
628  if self.children:
629  # the edge will come from my start vertex as I am a
630  # backward dependence
631  local_name += start_postfix
632  if remote_node:
633  # this node has a backward dependence.
634  remote_name = remote_node.dag_name
635  if remote_node.children:
636  # the remote node has children so I will connect to
637  # its end vertex
638  remote_name += end_postfix
639  # Create the backward dependence edge in red.
640  graph.edge(remote_name, local_name, color="red")
641  elif not isinstance(self, Routine):
642  # If this node is not a Routine (where the DAG context finishes)
643  # and has no backward dependence, connect it to the start vertex
644  # of its parent. Use blue to indicate a parent child
645  # relationship.
646  remote_name = self.parent.dag_name + start_postfix
647  graph.edge(remote_name, local_name, color="blue")
648  # now call any children so they can add their information to
649  # the graph
650  if isinstance(self, Loop):
651  # In case of a loop only look at the body (the other part
652  # of the tree contain start, stop, step values):
653  self.loop_body.dag_gen(graph)
654  else:
655  for child in self.children:
656  child.dag_gen(graph)
657 

References psyclone.gocean1p0.GOKernelGridArgument.backward_dependence(), psyclone.psyGen.Argument.backward_dependence(), psyclone.psyir.nodes.node.Node.backward_dependence(), psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, psyclone.psyir.nodes.node.Node.children(), psyclone.domain.common.psylayer.psyloop.PSyLoop.dag_name(), psyclone.psyGen.GlobalSum.dag_name(), psyclone.psyGen.HaloExchange.dag_name(), psyclone.psyGen.CodedKern.dag_name(), psyclone.psyGen.BuiltIn.dag_name(), psyclone.psyir.nodes.loop.Loop.dag_name(), psyclone.psyir.nodes.node.Node.dag_name(), psyclone.psyir.nodes.routine.Routine.dag_name(), psyclone.gocean1p0.GOKernelGridArgument.forward_dependence(), psyclone.psyGen.Argument.forward_dependence(), psyclone.psyir.nodes.node.Node.forward_dependence(), psyclone.psyir.nodes.loop.Loop.loop_body(), psyclone.psyir.nodes.while_loop.WhileLoop.loop_body(), psyclone.f2pygen.BaseGen.parent(), and psyclone.psyir.nodes.node.Node.parent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dag_name()

def psyclone.psyir.nodes.node.Node.dag_name (   self)
Return the dag name for this node. This includes the name of the
class and the index of its relative position to the parent Routine. If
no parent Routine is found, the index used is the absolute position
in the tree.

:returns: the dag name for this node.
:rtype: str

Reimplemented in psyclone.psyir.nodes.routine.Routine, and psyclone.psyir.nodes.loop.Loop.

Definition at line 659 of file node.py.

659  def dag_name(self):
660  '''Return the dag name for this node. This includes the name of the
661  class and the index of its relative position to the parent Routine. If
662  no parent Routine is found, the index used is the absolute position
663  in the tree.
664 
665  :returns: the dag name for this node.
666  :rtype: str
667 
668  '''
669  # Import here to avoid circular dependencies
670  # pylint: disable=import-outside-toplevel
671  from psyclone.psyir.nodes import Routine
672  if self.ancestor(Routine):
673  _, position = self._find_position(self.ancestor(Routine))
674  else:
675  position = self.abs_position
676  return self.coloured_name(False) + "_" + str(position)
677 

References psyclone.psyir.nodes.node.Node._find_position(), psyclone.psyir.nodes.node.Node.abs_position(), psyclone.psyir.nodes.node.Node.ancestor(), and psyclone.psyir.nodes.node.Node.coloured_name().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ debug_string()

def psyclone.psyir.nodes.node.Node.debug_string (   self)
 Generates a Fortran-like output representation but without
lowering high-level nodes. This is fast to generate because it
doesn't deepcopy the tree like the Language backends and its
output, although not compilable, is readable for error messages.

:returns: a Fortran-like output representation of the tree.
:rtype: str

Definition at line 1619 of file node.py.

1619  def debug_string(self):
1620  ''' Generates a Fortran-like output representation but without
1621  lowering high-level nodes. This is fast to generate because it
1622  doesn't deepcopy the tree like the Language backends and its
1623  output, although not compilable, is readable for error messages.
1624 
1625  :returns: a Fortran-like output representation of the tree.
1626  :rtype: str
1627 
1628  '''
1629  # Import outside top-level to avoid circular dependencies.
1630  # pylint: disable=import-outside-toplevel
1631  from psyclone.psyir.backend.debug_writer import DebugWriter
1632  return DebugWriter()(self)
1633 

◆ depth()

def psyclone.psyir.nodes.node.Node.depth (   self)
Returns this Node's depth in the tree: 1 for the Schedule
and increasing for its descendants at each level.
:returns: depth of the Node in the tree
:rtype: int

Definition at line 840 of file node.py.

840  def depth(self):
841  '''
842  Returns this Node's depth in the tree: 1 for the Schedule
843  and increasing for its descendants at each level.
844  :returns: depth of the Node in the tree
845  :rtype: int
846  '''
847  my_depth = self.START_DEPTH
848  node = self
849  while node is not None:
850  node = node.parent
851  my_depth += 1
852  return my_depth
853 

References psyclone.psyir.nodes.node.Node.START_DEPTH.

Here is the caller graph for this function:

◆ detach()

def psyclone.psyir.nodes.node.Node.detach (   self)
 Detach this node from the tree it belongs to. This is necessary
as a precursor to inserting it as the child of another node.

:returns: this node detached from its parent.
:rtype: :py:class:`psyclone.psyir.node.Node`

Definition at line 1554 of file node.py.

1554  def detach(self):
1555  ''' Detach this node from the tree it belongs to. This is necessary
1556  as a precursor to inserting it as the child of another node.
1557 
1558  :returns: this node detached from its parent.
1559  :rtype: :py:class:`psyclone.psyir.node.Node`
1560 
1561  '''
1562  if self.parent:
1563  index = self.position
1564  self.parent.children.pop(index)
1565  return self
1566 

References psyclone.psyir.nodes.node.Node._annotations, psyclone.f2pygen.BaseGen._children, psyclone.psyir.nodes.node.Node._children, psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._children_valid_format, psyclone.domain.common.algorithm.psyir.KernelFunctor._children_valid_format, psyclone.domain.lfric.algorithm.psyir.lfric_alg_invoke_call.LFRicAlgorithmInvokeCall._children_valid_format, psyclone.psyGen.GlobalSum._children_valid_format, psyclone.psyGen.HaloExchange._children_valid_format, psyclone.psyGen.Kern._children_valid_format, psyclone.psyGen.InlinedKern._children_valid_format, psyclone.psyir.nodes.acc_clauses.ACCCopyClause._children_valid_format, psyclone.psyir.nodes.acc_clauses.ACCCopyInClause._children_valid_format, psyclone.psyir.nodes.acc_clauses.ACCCopyOutClause._children_valid_format, psyclone.psyir.nodes.array_member.ArrayMember._children_valid_format, psyclone.psyir.nodes.array_of_structures_member.ArrayOfStructuresMember._children_valid_format, psyclone.psyir.nodes.array_of_structures_reference.ArrayOfStructuresReference._children_valid_format, psyclone.psyir.nodes.array_reference.ArrayReference._children_valid_format, psyclone.psyir.nodes.assignment.Assignment._children_valid_format, psyclone.psyir.nodes.call.Call._children_valid_format, psyclone.psyir.nodes.clause.Clause._children_valid_format, psyclone.psyir.nodes.codeblock.CodeBlock._children_valid_format, psyclone.psyir.nodes.container.Container._children_valid_format, psyclone.psyir.nodes.directive.RegionDirective._children_valid_format, psyclone.psyir.nodes.directive.StandaloneDirective._children_valid_format, psyclone.psyir.nodes.dynamic_omp_task_directive.DynamicOMPTaskDirective._children_valid_format, psyclone.psyir.nodes.if_block.IfBlock._children_valid_format, psyclone.psyir.nodes.intrinsic_call.IntrinsicCall._children_valid_format, psyclone.psyir.nodes.literal.Literal._children_valid_format, psyclone.psyir.nodes.loop.Loop._children_valid_format, psyclone.psyir.nodes.member.Member._children_valid_format, psyclone.psyir.nodes.node.Node._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPNowaitClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPGrainsizeClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPNumTasksClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPNogroupClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPSharedClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPPrivateClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPFirstprivateClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPDefaultClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPScheduleClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPDependClause._children_valid_format, psyclone.psyir.nodes.omp_clauses.OMPReductionClause._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPSingleDirective._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPTaskloopDirective._children_valid_format, psyclone.psyir.nodes.omp_directives.OMPParallelDoDirective._children_valid_format, psyclone.psyir.nodes.omp_task_directive.OMPTaskDirective._children_valid_format, psyclone.psyir.nodes.operation.UnaryOperation._children_valid_format, psyclone.psyir.nodes.operation.BinaryOperation._children_valid_format, psyclone.psyir.nodes.psy_data_node.PSyDataNode._children_valid_format, psyclone.psyir.nodes.ranges.Range._children_valid_format, psyclone.psyir.nodes.reference.Reference._children_valid_format, psyclone.psyir.nodes.return_stmt.Return._children_valid_format, psyclone.psyir.nodes.routine.Routine._children_valid_format, psyclone.psyir.nodes.schedule.Schedule._children_valid_format, psyclone.psyir.nodes.structure_member.StructureMember._children_valid_format, psyclone.psyir.nodes.structure_reference.StructureReference._children_valid_format, psyclone.psyir.nodes.while_loop.WhileLoop._children_valid_format, psyclone.psyir.nodes.node.Node._disable_tree_update, psyclone.psyir.nodes.node.Node._has_constructor_parent, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.GridArg._parent, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.FieldArg._parent, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.ScalarArg._parent, psyclone.domain.lfric.lfric_kern.LFRicKern._parent, psyclone.f2pygen.BaseGen._parent, psyclone.psyir.nodes.node.Node._parent, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._validate_child(), psyclone.domain.common.algorithm.psyir.KernelFunctor._validate_child(), psyclone.domain.lfric.algorithm.psyir.lfric_alg_invoke_call.LFRicAlgorithmInvokeCall._validate_child(), psyclone.psyGen.InlinedKern._validate_child(), psyclone.psyir.nodes.acc_clauses.ACCCopyClause._validate_child(), psyclone.psyir.nodes.acc_clauses.ACCCopyInClause._validate_child(), psyclone.psyir.nodes.acc_clauses.ACCCopyOutClause._validate_child(), psyclone.psyir.nodes.acc_directives.ACCDataDirective._validate_child(), psyclone.psyir.nodes.array_mixin.ArrayMixin._validate_child(), psyclone.psyir.nodes.array_of_structures_mixin.ArrayOfStructuresMixin._validate_child(), psyclone.psyir.nodes.assignment.Assignment._validate_child(), psyclone.psyir.nodes.call.Call._validate_child(), psyclone.psyir.nodes.container.Container._validate_child(), psyclone.psyir.nodes.directive.RegionDirective._validate_child(), psyclone.psyir.nodes.directive.StandaloneDirective._validate_child(), psyclone.psyir.nodes.if_block.IfBlock._validate_child(), psyclone.psyir.nodes.loop.Loop._validate_child(), psyclone.psyir.nodes.node.Node._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPGrainsizeClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPNumTasksClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPSharedClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPPrivateClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPFirstprivateClause._validate_child(), psyclone.psyir.nodes.omp_clauses.OMPDependClause._validate_child(), psyclone.psyir.nodes.omp_directives.OMPSingleDirective._validate_child(), psyclone.psyir.nodes.omp_directives.OMPParallelDirective._validate_child(), psyclone.psyir.nodes.omp_directives.OMPTaskloopDirective._validate_child(), psyclone.psyir.nodes.omp_directives.OMPParallelDoDirective._validate_child(), psyclone.psyir.nodes.omp_task_directive.OMPTaskDirective._validate_child(), psyclone.psyir.nodes.operation.UnaryOperation._validate_child(), psyclone.psyir.nodes.operation.BinaryOperation._validate_child(), psyclone.psyir.nodes.psy_data_node.PSyDataNode._validate_child(), psyclone.psyir.nodes.ranges.Range._validate_child(), psyclone.psyir.nodes.schedule.Schedule._validate_child(), psyclone.psyir.nodes.structure_member.StructureMember._validate_child(), psyclone.psyir.nodes.structure_reference.StructureReference._validate_child(), psyclone.psyir.nodes.while_loop.WhileLoop._validate_child(), psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, psyclone.psyir.nodes.node.Node.children(), psyclone.f2pygen.BaseGen.parent(), psyclone.psyir.nodes.node.Node.parent(), psyclone.f2pygen.Directive.position(), and psyclone.psyir.nodes.node.Node.position.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ following()

def psyclone.psyir.nodes.node.Node.following (   self,
  routine = True 
)
Return all :py:class:`psyclone.psyir.nodes.Node` nodes after this
node. Ordering is depth first. If the `routine` argument is
set to `True` then nodes are only returned if they are
descendents of this node's closest ancestor routine if one
exists.

:param bool routine: an optional (default `True`) argument \
    that only returns nodes that are within this node's \
    closest ancestor Routine node if one exists.

:returns: a list of nodes.
:rtype: :func:`list` of :py:class:`psyclone.psyir.nodes.Node`

Definition at line 1275 of file node.py.

1275  def following(self, routine=True):
1276  '''Return all :py:class:`psyclone.psyir.nodes.Node` nodes after this
1277  node. Ordering is depth first. If the `routine` argument is
1278  set to `True` then nodes are only returned if they are
1279  descendents of this node's closest ancestor routine if one
1280  exists.
1281 
1282  :param bool routine: an optional (default `True`) argument \
1283  that only returns nodes that are within this node's \
1284  closest ancestor Routine node if one exists.
1285 
1286  :returns: a list of nodes.
1287  :rtype: :func:`list` of :py:class:`psyclone.psyir.nodes.Node`
1288 
1289  '''
1290  root = self.root
1291  if routine:
1292  # Import here to avoid circular dependencies
1293  # pylint: disable=import-outside-toplevel
1294  from psyclone.psyir.nodes import Routine
1295  # If there is an ancestor Routine node then only return nodes
1296  # that are within it.
1297  routine_node = self.ancestor(Routine)
1298  if routine_node:
1299  root = routine_node
1300  all_nodes = root.walk(Node)
1301  position = None
1302  for index, node in enumerate(all_nodes):
1303  if node is self:
1304  position = index
1305  break
1306 
1307  return all_nodes[position+1:]
1308 

References psyclone.psyir.nodes.node.Node.ancestor(), psyclone.f2pygen.BaseGen.root(), psyclone.f2pygen.BaseDeclGen.root(), and psyclone.psyir.nodes.node.Node.root().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ forward_dependence()

def psyclone.psyir.nodes.node.Node.forward_dependence (   self)
Returns the closest following Node that this Node has a direct
dependence with or None if there is not one. Only Nodes with
the same parent as self are returned. Nodes inherit their
descendants' dependencies. The reason for this is that for
correctness a node must maintain its parent if it is
moved. For example a halo exchange and a kernel call may have
a dependence between them but it is the loop body containing
the kernel call that the halo exchange must not move beyond
i.e. the loop body inherits the dependencies of the routines
within it.

Definition at line 727 of file node.py.

727  def forward_dependence(self):
728  '''Returns the closest following Node that this Node has a direct
729  dependence with or None if there is not one. Only Nodes with
730  the same parent as self are returned. Nodes inherit their
731  descendants' dependencies. The reason for this is that for
732  correctness a node must maintain its parent if it is
733  moved. For example a halo exchange and a kernel call may have
734  a dependence between them but it is the loop body containing
735  the kernel call that the halo exchange must not move beyond
736  i.e. the loop body inherits the dependencies of the routines
737  within it.'''
738  dependence = None
739  # look through all the forward dependencies of my arguments
740  for arg in self.args:
741  dependent_arg = arg.forward_dependence()
742  if dependent_arg:
743  # this argument has a forward dependence
744  node = dependent_arg.call
745  # if the remote node is deeper in the tree than me
746  # then find the ancestor that is at the same level of
747  # the tree as me.
748  while node.depth > self.depth:
749  node = node.parent
750  if self.sameParent(node) and node is not self:
751  # The remote node (or one of its ancestors) shares
752  # the same parent as me (but its not me)
753  if not dependence:
754  # this is the first dependence found so keep it
755  dependence = node
756  else:
757  if dependence.position > node.position:
758  # the new dependence is closer to me than
759  # the previous dependence so keep it
760  dependence = node
761  return dependence
762 

References psyclone.expression.FunctionVar.args, psyclone.f2pygen.SubroutineGen.args(), psyclone.parse.algorithm.ParsedCall.args(), psyclone.psyGen.GlobalSum.args(), psyclone.psyGen.HaloExchange.args(), psyclone.psyGen.Kern.args(), psyclone.psyGen.Arguments.args(), psyclone.psyir.nodes.node.Node.args(), psyclone.psyir.nodes.node.Node.depth(), psyclone.gocean1p0.GOStencil.depth(), and psyclone.psyir.nodes.node.Node.sameParent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_sibling_lists()

def psyclone.psyir.nodes.node.Node.get_sibling_lists (   self,
  my_type,
  stop_type = None 
)
Recurse through the PSyIR tree and return lists of Nodes that are
instances of 'my_type' and are immediate siblings. Here 'my_type' is
either a single class or a tuple of classes. In the latter case all
nodes are returned that are instances of any classes in the tuple. The
recursion into the tree is stopped if an instance of 'stop_type' (which
is either a single class or a tuple of classes) is found.

:param my_type: the class(es) for which the instances are collected.
:type my_type: type | Tuple[type, ...]
:param stop_type: class(es) at which recursion is halted (optional).
:type stop_type: Optional[type | Tuple[type, ...]]

:returns: list of lists, each of which containing nodes that are
          instances of my_type and are immediate siblings, starting at
          and including this node.
:rtype: List[List[:py:class:`psyclone.psyir.nodes.Node`]]

Definition at line 1116 of file node.py.

1116  def get_sibling_lists(self, my_type, stop_type=None):
1117  '''
1118  Recurse through the PSyIR tree and return lists of Nodes that are
1119  instances of 'my_type' and are immediate siblings. Here 'my_type' is
1120  either a single class or a tuple of classes. In the latter case all
1121  nodes are returned that are instances of any classes in the tuple. The
1122  recursion into the tree is stopped if an instance of 'stop_type' (which
1123  is either a single class or a tuple of classes) is found.
1124 
1125  :param my_type: the class(es) for which the instances are collected.
1126  :type my_type: type | Tuple[type, ...]
1127  :param stop_type: class(es) at which recursion is halted (optional).
1128  :type stop_type: Optional[type | Tuple[type, ...]]
1129 
1130  :returns: list of lists, each of which containing nodes that are
1131  instances of my_type and are immediate siblings, starting at
1132  and including this node.
1133  :rtype: List[List[:py:class:`psyclone.psyir.nodes.Node`]]
1134 
1135  '''
1136  # Separate nodes by depth
1137  by_depth = {}
1138  for node in self.walk(my_type, stop_type=stop_type):
1139  depth = node.depth
1140  if depth not in by_depth:
1141  by_depth[depth] = []
1142  by_depth[depth].append(node)
1143 
1144  # Determine lists of consecutive nodes
1145  global_list = []
1146  for depth, local_list in sorted(by_depth.items()):
1147  block = []
1148  for node in local_list:
1149  if not block or node.immediately_follows(block[-1]):
1150  block.append(node)
1151  else:
1152  # Current node does not immediately follow the previous one
1153  # so this marks the end of the current block.
1154  global_list.append(block)
1155  block = [node]
1156  if block:
1157  global_list.append(block)
1158  return global_list
1159 

References psyclone.psyir.nodes.node.Node.walk().

Here is the call graph for this function:

◆ has_constructor_parent()

def psyclone.psyir.nodes.node.Node.has_constructor_parent (   self)
:returns: whether the constructor has predefined a parent connection
    but the parent's children list doesn't include this node yet.
:rtype: bool

Definition at line 970 of file node.py.

970  def has_constructor_parent(self):
971  '''
972  :returns: whether the constructor has predefined a parent connection
973  but the parent's children list doesn't include this node yet.
974  :rtype: bool
975  '''
976  return self._has_constructor_parent
977 

References psyclone.psyir.nodes.node.Node._has_constructor_parent.

◆ immediately_follows()

def psyclone.psyir.nodes.node.Node.immediately_follows (   self,
  node_1 
)
:returns: True if this node immediately follows `node_1`, False
          otherwise
:rtype: bool

Definition at line 1362 of file node.py.

1362  def immediately_follows(self, node_1):
1363  '''
1364  :returns: True if this node immediately follows `node_1`, False
1365  otherwise
1366  :rtype: bool
1367  '''
1368  return (
1369  self.sameParent(node_1)
1370  and self in node_1.following()
1371  and self.position == node_1.position + 1
1372  )
1373 

References psyclone.f2pygen.Directive.position(), psyclone.psyir.nodes.node.Node.position, and psyclone.psyir.nodes.node.Node.sameParent().

Here is the call graph for this function:

◆ immediately_precedes()

def psyclone.psyir.nodes.node.Node.immediately_precedes (   self,
  node_2 
)
:returns: True if this node immediately precedes `node_2`, False
          otherwise
:rtype: bool

Definition at line 1350 of file node.py.

1350  def immediately_precedes(self, node_2):
1351  '''
1352  :returns: True if this node immediately precedes `node_2`, False
1353  otherwise
1354  :rtype: bool
1355  '''
1356  return (
1357  self.sameParent(node_2)
1358  and self in node_2.preceding()
1359  and self.position + 1 == node_2.position
1360  )
1361 

References psyclone.f2pygen.Directive.position(), psyclone.psyir.nodes.node.Node.position, and psyclone.psyir.nodes.node.Node.sameParent().

Here is the call graph for this function:

◆ is_openmp_parallel()

def psyclone.psyir.nodes.node.Node.is_openmp_parallel (   self)
:returns: True if this Node is within an OpenMP parallel region, \
          False otherwise.
:rtype: bool

Definition at line 1429 of file node.py.

1429  def is_openmp_parallel(self):
1430  '''
1431  :returns: True if this Node is within an OpenMP parallel region, \
1432  False otherwise.
1433  :rtype: bool
1434 
1435  '''
1436  # pylint: disable=import-outside-toplevel
1437  from psyclone.psyir.nodes import OMPParallelDirective
1438  omp_dir = self.ancestor(OMPParallelDirective)
1439  if omp_dir:
1440  return True
1441  return False
1442 

References psyclone.psyir.nodes.node.Node.ancestor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_valid_location()

def psyclone.psyir.nodes.node.Node.is_valid_location (   self,
  new_node,
  position = "before" 
)
If this Node can be moved to the new_node
(where position determines whether it is before of after the
new_node) without breaking any data dependencies then return True,
otherwise return False.

:param new_node: Node to which this node should be moved.
:type new_node: :py:class:`psyclone.psyir.nodes.Node`
:param str position: either 'before' or 'after'.

:raises GenerationError: if new_node is not an\
        instance of :py:class:`psyclone.psyir.nodes.Node`.
:raises GenerationError: if position is not 'before' or 'after'.
:raises GenerationError: if self and new_node do not have the same\
        parent.
:raises GenerationError: self and new_node are the same Node.

:returns: whether or not the specified location is valid for this node.
:rtype: bool

Definition at line 763 of file node.py.

763  def is_valid_location(self, new_node, position="before"):
764  '''If this Node can be moved to the new_node
765  (where position determines whether it is before of after the
766  new_node) without breaking any data dependencies then return True,
767  otherwise return False.
768 
769  :param new_node: Node to which this node should be moved.
770  :type new_node: :py:class:`psyclone.psyir.nodes.Node`
771  :param str position: either 'before' or 'after'.
772 
773  :raises GenerationError: if new_node is not an\
774  instance of :py:class:`psyclone.psyir.nodes.Node`.
775  :raises GenerationError: if position is not 'before' or 'after'.
776  :raises GenerationError: if self and new_node do not have the same\
777  parent.
778  :raises GenerationError: self and new_node are the same Node.
779 
780  :returns: whether or not the specified location is valid for this node.
781  :rtype: bool
782 
783  '''
784  # First perform correctness checks
785  # 1: check new_node is a Node
786  if not isinstance(new_node, Node):
787  raise GenerationError(
788  f"In the psyir.nodes.Node.is_valid_location() method the "
789  f"supplied argument is not a Node, it is a "
790  f"'{type(new_node).__name__}'.")
791 
792  # 2: check position has a valid value
793  valid_positions = ["before", "after"]
794  if position not in valid_positions:
795  raise GenerationError(
796  f"The position argument in the psyGenNode.is_valid_location() "
797  f"method must be one of {valid_positions} but found "
798  f"'{position}'")
799 
800  # 3: check self and new_node have the same parent
801  if not self.sameParent(new_node):
802  raise GenerationError(
803  "In the psyir.nodes.Node.is_valid_location() method "
804  "the node and the location do not have the same parent")
805 
806  # 4: check proposed new position is not the same as current position
807  new_position = new_node.position
808  if new_position < self.position and position == "after":
809  new_position += 1
810  elif new_position > self.position and position == "before":
811  new_position -= 1
812 
813  if self.position == new_position:
814  raise GenerationError(
815  "In the psyir.nodes.Node.is_valid_location() method, the "
816  "node and the location are the same so this transformation "
817  "would have no effect.")
818 
819  # Now determine whether the new location is valid in terms of
820  # data dependencies
821  # Treat forward and backward dependencies separately
822  if new_position < self.position:
823  # the new_node is before this node in the schedule
824  prev_dep_node = self.backward_dependence()
825  if not prev_dep_node:
826  # There are no backward dependencies so the move is valid
827  return True
828  # return (is the dependent node before the new_position?)
829  return prev_dep_node.position < new_position
830  # new_node.position > self.position
831  # the new_node is after this node in the schedule
832  next_dep_node = self.forward_dependence()
833  if not next_dep_node:
834  # There are no forward dependencies so the move is valid
835  return True
836  # return (is the dependent node after the new_position?)
837  return next_dep_node.position > new_position
838 

References psyclone.gocean1p0.GOKernelGridArgument.backward_dependence(), psyclone.psyGen.Argument.backward_dependence(), psyclone.psyir.nodes.node.Node.backward_dependence(), psyclone.gocean1p0.GOKernelGridArgument.forward_dependence(), psyclone.psyGen.Argument.forward_dependence(), psyclone.psyir.nodes.node.Node.forward_dependence(), psyclone.f2pygen.Directive.position(), psyclone.psyir.nodes.node.Node.position, and psyclone.psyir.nodes.node.Node.sameParent().

Here is the call graph for this function:

◆ kernels()

def psyclone.psyir.nodes.node.Node.kernels (   self)
:returns: all kernels that are descendants of this node in the PSyIR.
:rtype: List[:py:class:`psyclone.psyGen.Kern`]

Definition at line 1266 of file node.py.

1266  def kernels(self):
1267  '''
1268  :returns: all kernels that are descendants of this node in the PSyIR.
1269  :rtype: List[:py:class:`psyclone.psyGen.Kern`]
1270  '''
1271  # pylint: disable=import-outside-toplevel
1272  from psyclone.psyGen import Kern
1273  return self.walk(Kern)
1274 

References psyclone.psyir.nodes.node.Node.walk().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ loops()

def psyclone.psyir.nodes.node.Node.loops (   self)
:returns: all loops currently in this schedule.
:rtype: List[:py:class:`psyclone.psyir.nodes.Loop`]

Definition at line 1387 of file node.py.

1387  def loops(self):
1388  '''
1389  :returns: all loops currently in this schedule.
1390  :rtype: List[:py:class:`psyclone.psyir.nodes.Loop`]
1391  '''
1392  # pylint: disable=import-outside-toplevel
1393  from psyclone.psyir.nodes import Loop
1394  return self.walk(Loop)
1395 

References psyclone.psyir.nodes.node.Node.walk().

Here is the call graph for this function:

◆ lower_to_language_level()

def psyclone.psyir.nodes.node.Node.lower_to_language_level (   self)
In-place replacement of high-level concepts into generic language
PSyIR constructs. This generic implementation only recurses down
to its children, but this method must be re-implemented by Nodes
that represent high-level concepts.

:returns: the lowered version of this node.
:rtype: :py:class:`psyclone.psyir.node.Node`

Reimplemented in psyclone.psyir.nodes.read_only_verify_node.ReadOnlyVerifyNode, psyclone.psyir.nodes.omp_directives.OMPParallelDoDirective, psyclone.psyir.nodes.omp_directives.OMPParallelDirective, psyclone.psyir.nodes.omp_directives.OMPSerialDirective, psyclone.psyir.nodes.nan_test_node.NanTestNode, psyclone.psyir.nodes.extract_node.ExtractNode, psyclone.psyir.nodes.dynamic_omp_task_directive.DynamicOMPTaskDirective, and psyclone.psyir.nodes.acc_directives.ACCEnterDataDirective.

Definition at line 1443 of file node.py.

1443  def lower_to_language_level(self):
1444  '''
1445  In-place replacement of high-level concepts into generic language
1446  PSyIR constructs. This generic implementation only recurses down
1447  to its children, but this method must be re-implemented by Nodes
1448  that represent high-level concepts.
1449 
1450  :returns: the lowered version of this node.
1451  :rtype: :py:class:`psyclone.psyir.node.Node`
1452 
1453  '''
1454  # We recurse only over the original children (hence [:]), this is
1455  # because new nodes may be inserted during the lowering, but these
1456  # must already be language-level.
1457  for child in self.children[:]:
1458  child.lower_to_language_level()
1459  return self
1460 

References psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, and psyclone.psyir.nodes.node.Node.children().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ node_str()

def psyclone.psyir.nodes.node.Node.node_str (   self,
  colour = True 
)
:param bool colour: whether or not to include control codes for \
                    coloured text.

:returns: a text description of this node. Will typically be \
          overridden by sub-class.
:rtype: str

Reimplemented in psyclone.psyir.nodes.routine.Routine, psyclone.psyir.nodes.reference.Reference, psyclone.psyir.nodes.operation.Operation, psyclone.psyir.nodes.omp_directives.OMPLoopDirective, psyclone.psyir.nodes.omp_directives.OMPDoDirective, psyclone.psyir.nodes.omp_clauses.OMPDependClause, psyclone.psyir.nodes.omp_clauses.OMPScheduleClause, psyclone.psyir.nodes.omp_clauses.OMPDefaultClause, psyclone.psyir.nodes.member.Member, psyclone.psyir.nodes.loop.Loop, psyclone.psyir.nodes.literal.Literal, psyclone.psyir.nodes.file_container.FileContainer, psyclone.psyir.nodes.container.Container, psyclone.psyir.nodes.codeblock.CodeBlock, psyclone.psyir.nodes.call.Call, and psyclone.psyir.nodes.acc_directives.ACCLoopDirective.

Definition at line 483 of file node.py.

483  def node_str(self, colour=True):
484  '''
485  :param bool colour: whether or not to include control codes for \
486  coloured text.
487 
488  :returns: a text description of this node. Will typically be \
489  overridden by sub-class.
490  :rtype: str
491  '''
492  text = self.coloured_name(colour) + "["
493  if self.annotations:
494  text += "annotations='" + ','.join(self.annotations) + "'"
495  text += "]"
496  return text
497 

References psyclone.psyir.nodes.node.Node.annotations(), psyclone.psyir.nodes.node.Node.coloured_name(), psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall.node_str(), psyclone.domain.common.psylayer.psyloop.PSyLoop.node_str(), psyclone.domain.lfric.lfric_invoke_schedule.LFRicInvokeSchedule.node_str(), psyclone.domain.lfric.lfric_loop.LFRicLoop.node_str(), psyclone.dynamo0p3.LFRicHaloExchange.node_str(), psyclone.psyGen.InvokeSchedule.node_str(), psyclone.psyGen.GlobalSum.node_str(), psyclone.psyGen.HaloExchange.node_str(), psyclone.psyGen.Kern.node_str(), psyclone.psyGen.CodedKern.node_str(), psyclone.psyGen.InlinedKern.node_str(), psyclone.psyir.nodes.acc_directives.ACCLoopDirective.node_str(), psyclone.psyir.nodes.call.Call.node_str(), psyclone.psyir.nodes.codeblock.CodeBlock.node_str(), psyclone.psyir.nodes.container.Container.node_str(), psyclone.psyir.nodes.file_container.FileContainer.node_str(), psyclone.psyir.nodes.literal.Literal.node_str(), psyclone.psyir.nodes.loop.Loop.node_str(), psyclone.psyir.nodes.member.Member.node_str(), psyclone.psyir.nodes.node.Node.node_str(), psyclone.psyir.nodes.omp_clauses.OMPDefaultClause.node_str(), psyclone.psyir.nodes.omp_clauses.OMPScheduleClause.node_str(), psyclone.psyir.nodes.omp_clauses.OMPDependClause.node_str(), psyclone.psyir.nodes.omp_directives.OMPDoDirective.node_str(), psyclone.psyir.nodes.omp_directives.OMPLoopDirective.node_str(), psyclone.psyir.nodes.operation.Operation.node_str(), psyclone.psyir.nodes.reference.Reference.node_str(), and psyclone.psyir.nodes.routine.Routine.node_str().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ origin_string()

def psyclone.psyir.nodes.node.Node.origin_string (   self)
 Generates a string with the available information about where
this node has been created. It currently only works with Fortran
Statements or subchildren of them.

:returns: a string specifing the origin of this node.
:rtype: str

Definition at line 1634 of file node.py.

1634  def origin_string(self):
1635  ''' Generates a string with the available information about where
1636  this node has been created. It currently only works with Fortran
1637  Statements or subchildren of them.
1638 
1639  :returns: a string specifing the origin of this node.
1640  :rtype: str
1641  '''
1642  name = self.coloured_name(False)
1643  line_span = "<unknown>"
1644  original_src = "<unknown>"
1645  filename = "<unknown>"
1646  # Try to populate the line/src/filename using the ancestor Statement
1647  from psyclone.psyir.nodes.statement import Statement
1648  node = self.ancestor(Statement, include_self=True)
1649  # TODO #2062: The part below is tighly coupled to fparser tree
1650  # structure and ideally should be moved the appropriate frontend,
1651  # but we don't necessarely want to do all this string manipulation
1652  # ahead of time as it is rarely needed. One option is for the frontend
1653  # to provide a callable that this method will invoke to generate the
1654  # string. Other frontends or PSyIR not comming from code could provide
1655  # a completely different implementation in the Callable oject.
1656  if node and node._ast:
1657  if hasattr(node._ast, 'item') and node._ast.item:
1658  if hasattr(node._ast.item, 'reader'):
1659  if hasattr(node._ast.item.reader, 'file'):
1660  filename = node._ast.item.reader.file.name
1661  line_span = node._ast.item.span
1662  original_src = node._ast.item.line
1663  return (f"{name} from line {line_span} of file "
1664  f"'{filename}':\n> {original_src}")
1665 

References psyclone.psyir.nodes.node.Node.ancestor(), and psyclone.psyir.nodes.node.Node.coloured_name().

Here is the call graph for this function:

◆ parent()

def psyclone.psyir.nodes.node.Node.parent (   self)
:returns: the parent node.
:rtype: :py:class:`psyclone.psyir.nodes.Node` or NoneType

Definition at line 953 of file node.py.

953  def parent(self):
954  '''
955  :returns: the parent node.
956  :rtype: :py:class:`psyclone.psyir.nodes.Node` or NoneType
957  '''
958  return self._parent
959 

References psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.GridArg._parent, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.FieldArg._parent, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.ScalarArg._parent, psyclone.domain.lfric.lfric_kern.LFRicKern._parent, psyclone.f2pygen.BaseGen._parent, and psyclone.psyir.nodes.node.Node._parent.

Here is the caller graph for this function:

◆ path_from()

def psyclone.psyir.nodes.node.Node.path_from (   self,
  ancestor 
)
 Find the path in the psyir tree between ancestor and node and
returns a list containing the path.

The result of this method can be used to find the node from its
ancestor for example by:

>>> index_list = node.path_from(ancestor)
>>> cursor = ancestor
>>> for index in index_list:
>>>    cursor = cursor.children[index]
>>> assert cursor is node

:param ancestor: an ancestor node of self to find the path from.
:type ancestor: :py:class:`psyclone.psyir.nodes.Node`

:raises ValueError: if ancestor is not an ancestor of self.

:returns: a list of child indices representing the path between
          ancestor and self.
:rtype: List[int]

Definition at line 1700 of file node.py.

1700  def path_from(self, ancestor):
1701  ''' Find the path in the psyir tree between ancestor and node and
1702  returns a list containing the path.
1703 
1704  The result of this method can be used to find the node from its
1705  ancestor for example by:
1706 
1707  >>> index_list = node.path_from(ancestor)
1708  >>> cursor = ancestor
1709  >>> for index in index_list:
1710  >>> cursor = cursor.children[index]
1711  >>> assert cursor is node
1712 
1713  :param ancestor: an ancestor node of self to find the path from.
1714  :type ancestor: :py:class:`psyclone.psyir.nodes.Node`
1715 
1716  :raises ValueError: if ancestor is not an ancestor of self.
1717 
1718  :returns: a list of child indices representing the path between
1719  ancestor and self.
1720  :rtype: List[int]
1721  '''
1722  result_list = []
1723  current_node = self
1724  while current_node is not ancestor and current_node.parent is not None:
1725  result_list.append(current_node.position)
1726  current_node = current_node.parent
1727 
1728  if current_node is not ancestor:
1729  raise ValueError(f"Attempted to find path_from a non-ancestor "
1730  f"'{type(ancestor).__name__}' node.")
1731 
1732  result_list.reverse()
1733  return result_list
1734 
1735 
1736 # For automatic documentation generation
1737 # TODO #913 the 'colored' routine shouldn't be in this module.

◆ pop_all_children()

def psyclone.psyir.nodes.node.Node.pop_all_children (   self)
 Remove all children of this node and return them as a list.

:returns: all the children of this node as orphan nodes.
:rtype: list of :py:class:`psyclone.psyir.node.Node`

Definition at line 1542 of file node.py.

1542  def pop_all_children(self):
1543  ''' Remove all children of this node and return them as a list.
1544 
1545  :returns: all the children of this node as orphan nodes.
1546  :rtype: list of :py:class:`psyclone.psyir.node.Node`
1547 
1548  '''
1549  free_children = []
1550  while self.children:
1551  free_children.insert(0, self.children.pop())
1552  return free_children
1553 

References psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, and psyclone.psyir.nodes.node.Node.children().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ position()

def psyclone.psyir.nodes.node.Node.position (   self)
Find a Node's position relative to its parent Node (starting
with 0 if it does not have a parent).

:returns: relative position of a Node to its parent
:rtype: int

Definition at line 979 of file node.py.

979  def position(self):
980  '''
981  Find a Node's position relative to its parent Node (starting
982  with 0 if it does not have a parent).
983 
984  :returns: relative position of a Node to its parent
985  :rtype: int
986  '''
987  if self.parent is None:
988  return self.START_POSITION
989  for index, child in enumerate(self.parent.children):
990  if child is self:
991  return index
992 

References psyclone.f2pygen.BaseGen.parent(), psyclone.psyir.nodes.node.Node.parent(), and psyclone.psyir.nodes.node.Node.START_POSITION.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ preceding()

def psyclone.psyir.nodes.node.Node.preceding (   self,
  reverse = False,
  routine = True 
)
Return all :py:class:`psyclone.psyir.nodes.Node` nodes before this
node. Ordering is depth first. If the `reverse` argument is
set to `True` then the node ordering is reversed
i.e. returning the nodes closest to this node first. if the
`routine` argument is set to `True` then nodes are only
returned if they are descendents of this node's closest
ancestor routine if one exists.

:param bool reverse: an optional (default `False`) argument \
    that reverses the order of any returned nodes (i.e. makes \
    them 'closest first' if set to true.
:param bool routine: an optional (default `True`) argument \
    that only returns nodes that are within this node's \
    closest ancestor Routine node if one exists.

:returns: a list of nodes.
:rtype: :func:`list` of :py:class:`psyclone.psyir.nodes.Node`

Definition at line 1309 of file node.py.

1309  def preceding(self, reverse=False, routine=True):
1310  '''Return all :py:class:`psyclone.psyir.nodes.Node` nodes before this
1311  node. Ordering is depth first. If the `reverse` argument is
1312  set to `True` then the node ordering is reversed
1313  i.e. returning the nodes closest to this node first. if the
1314  `routine` argument is set to `True` then nodes are only
1315  returned if they are descendents of this node's closest
1316  ancestor routine if one exists.
1317 
1318  :param bool reverse: an optional (default `False`) argument \
1319  that reverses the order of any returned nodes (i.e. makes \
1320  them 'closest first' if set to true.
1321  :param bool routine: an optional (default `True`) argument \
1322  that only returns nodes that are within this node's \
1323  closest ancestor Routine node if one exists.
1324 
1325  :returns: a list of nodes.
1326  :rtype: :func:`list` of :py:class:`psyclone.psyir.nodes.Node`
1327 
1328  '''
1329  root = self.root
1330  if routine:
1331  # Import here to avoid circular dependencies
1332  # pylint: disable=import-outside-toplevel
1333  from psyclone.psyir.nodes import Routine
1334  # If there is an ancestor Routine node then only return nodes
1335  # that are within it.
1336  routine_node = self.ancestor(Routine)
1337  if routine_node:
1338  root = routine_node
1339  all_nodes = root.walk(Node)
1340  position = None
1341  for index, node in enumerate(all_nodes):
1342  if node is self:
1343  position = index
1344  break
1345  nodes = all_nodes[:position]
1346  if reverse:
1347  nodes.reverse()
1348  return nodes
1349 

References psyclone.psyir.nodes.node.Node.ancestor(), psyclone.f2pygen.BaseGen.root(), psyclone.f2pygen.BaseDeclGen.root(), and psyclone.psyir.nodes.node.Node.root().

Here is the call graph for this function:

◆ reductions()

def psyclone.psyir.nodes.node.Node.reductions (   self,
  reprod = None 
)
Return all kernels that have reductions and are decendents of this
node. If reprod is not provided, all reductions are
returned. If reprod is False, all builtin reductions that are
not set to reproducible are returned. If reprod is True, all
builtins that are set to reproducible are returned.

:param reprod: if provided, filter reductions by whether or not they \
               are set to be reproducible.
:type reprod: Optional[bool]

:returns: all kernels involving reductions that are descendants of \
          this node.
:rtype: List[:py:class:`psyclone.psyir.nodes.Kern`]

Definition at line 1396 of file node.py.

1396  def reductions(self, reprod=None):
1397  '''
1398  Return all kernels that have reductions and are decendents of this
1399  node. If reprod is not provided, all reductions are
1400  returned. If reprod is False, all builtin reductions that are
1401  not set to reproducible are returned. If reprod is True, all
1402  builtins that are set to reproducible are returned.
1403 
1404  :param reprod: if provided, filter reductions by whether or not they \
1405  are set to be reproducible.
1406  :type reprod: Optional[bool]
1407 
1408  :returns: all kernels involving reductions that are descendants of \
1409  this node.
1410  :rtype: List[:py:class:`psyclone.psyir.nodes.Kern`]
1411 
1412  '''
1413  # pylint: disable=import-outside-toplevel
1414  from psyclone.psyGen import Kern
1415 
1416  call_reduction_list = []
1417  for call in self.walk(Kern):
1418  if call.is_reduction:
1419  if reprod is None:
1420  call_reduction_list.append(call)
1421  elif reprod:
1422  if call.reprod_reduction:
1423  call_reduction_list.append(call)
1424  else:
1425  if not call.reprod_reduction:
1426  call_reduction_list.append(call)
1427  return call_reduction_list
1428 

References psyclone.psyir.nodes.node.Node.walk().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reference_accesses()

def psyclone.psyir.nodes.node.Node.reference_accesses (   self,
  var_accesses 
)
Get all variable access information. The default implementation
just recurses down to all children.

:param var_accesses: Stores the output results.
:type var_accesses: \
    :py:class:`psyclone.core.VariablesAccessInfo`

Reimplemented in psyclone.psyir.nodes.while_loop.WhileLoop, psyclone.psyir.nodes.reference.Reference, psyclone.psyir.nodes.loop.Loop, psyclone.psyir.nodes.intrinsic_call.IntrinsicCall, psyclone.psyir.nodes.if_block.IfBlock, psyclone.psyir.nodes.call.Call, and psyclone.psyir.nodes.assignment.Assignment.

Definition at line 1461 of file node.py.

1461  def reference_accesses(self, var_accesses):
1462  '''Get all variable access information. The default implementation
1463  just recurses down to all children.
1464 
1465  :param var_accesses: Stores the output results.
1466  :type var_accesses: \
1467  :py:class:`psyclone.core.VariablesAccessInfo`
1468  '''
1469  for child in self._children:
1470  child.reference_accesses(var_accesses)
1471 

References psyclone.f2pygen.BaseGen._children, psyclone.psyir.nodes.node.Node._children, and psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children.

Here is the caller graph for this function:

◆ replace_with()

def psyclone.psyir.nodes.node.Node.replace_with (   self,
  node,
  keep_name_in_context = True 
)
Removes self, and its descendants, from the PSyIR tree to which it
is connected, and replaces it with the supplied node (and its
descendants).

:param node: the node that will replace self in the PSyIR \
    tree.
:type node: :py:class:`psyclone.psyir.nodes.node`
:param bool keep_name_in_context: whether to conserve the name \
    referencing this node.

:raises TypeError: if the argument 'node' is not a Node.
:raises TypeError: if the argument 'keep_name_in_context' is not bool.
:raises GenerationError: if this node does not have a parent.
:raises GenerationError: if the argument 'node' has a parent.

Definition at line 1495 of file node.py.

1495  def replace_with(self, node, keep_name_in_context=True):
1496  '''Removes self, and its descendants, from the PSyIR tree to which it
1497  is connected, and replaces it with the supplied node (and its
1498  descendants).
1499 
1500  :param node: the node that will replace self in the PSyIR \
1501  tree.
1502  :type node: :py:class:`psyclone.psyir.nodes.node`
1503  :param bool keep_name_in_context: whether to conserve the name \
1504  referencing this node.
1505 
1506  :raises TypeError: if the argument 'node' is not a Node.
1507  :raises TypeError: if the argument 'keep_name_in_context' is not bool.
1508  :raises GenerationError: if this node does not have a parent.
1509  :raises GenerationError: if the argument 'node' has a parent.
1510 
1511  '''
1512  if not isinstance(node, Node):
1513  raise TypeError(
1514  f"The argument node in method replace_with in the Node class "
1515  f"should be a Node but found '{type(node).__name__}'.")
1516  if not isinstance(keep_name_in_context, bool):
1517  raise TypeError(
1518  f"The argument keep_name_in_context in method replace_with in "
1519  f"the Node class should be a bool but found "
1520  f"'{type(keep_name_in_context).__name__}'.")
1521  if not self.parent:
1522  raise GenerationError(
1523  "This node should have a parent if its replace_with method "
1524  "is called.")
1525  if node.parent is not None:
1526  raise GenerationError(
1527  f"The parent of argument node in method replace_with in the "
1528  f"Node class should be None but found "
1529  f"'{type(node.parent).__name__}'.")
1530 
1531  # The n'th argument is placed at the n'th+1 children position
1532  # because the 1st child is the routine reference
1533  if keep_name_in_context and hasattr(self.parent, "argument_names") \
1534  and self.parent.argument_names[self.position - 1] is not None:
1535  # If it is a named context it will have a specific method for
1536  # replacing the node while keeping the name
1537  name = self.parent.argument_names[self.position - 1]
1538  self.parent.replace_named_arg(name, node)
1539  else:
1540  self.parent.children[self.position] = node
1541 

References psyclone.f2pygen.BaseGen.parent(), psyclone.psyir.nodes.node.Node.parent(), psyclone.f2pygen.Directive.position(), and psyclone.psyir.nodes.node.Node.position.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ root()

def psyclone.psyir.nodes.node.Node.root (   self)
:returns: the root node of the PSyIR tree.
:rtype: :py:class:`psyclone.psyir.nodes.Node`

Definition at line 1049 of file node.py.

1049  def root(self):
1050  '''
1051  :returns: the root node of the PSyIR tree.
1052  :rtype: :py:class:`psyclone.psyir.nodes.Node`
1053 
1054  '''
1055  # Starting with 'self.parent' instead of 'node = self' avoids many
1056  # false positive pylint issues that assume self.root type would be
1057  # the same as self type.
1058  if self.parent is None:
1059  return self
1060  node = self.parent
1061  while node.parent is not None:
1062  node = node.parent
1063  return node
1064 

References psyclone.f2pygen.BaseGen.parent(), and psyclone.psyir.nodes.node.Node.parent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sameParent()

def psyclone.psyir.nodes.node.Node.sameParent (   self,
  node_2 
)
:returns: True if `node_2` has the same parent as this node, False \
          otherwise.
:rtype: bool

Definition at line 1065 of file node.py.

1065  def sameParent(self, node_2):
1066  '''
1067  :returns: True if `node_2` has the same parent as this node, False \
1068  otherwise.
1069  :rtype: bool
1070  '''
1071  if self.parent is None or node_2.parent is None:
1072  return False
1073  return self.parent is node_2.parent
1074 

References psyclone.f2pygen.BaseGen.parent(), and psyclone.psyir.nodes.node.Node.parent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ scope()

def psyclone.psyir.nodes.node.Node.scope (   self)
 Some nodes (e.g. Schedule and Container) allow symbols to be
scoped via an attached symbol table. This property returns the closest
ScopingNode node including self.

:returns: the closest ancestor ScopingNode node.
:rtype: :py:class:`psyclone.psyir.node.ScopingNode`

:raises SymbolError: if there is no ScopingNode ancestor.

Definition at line 1473 of file node.py.

1473  def scope(self):
1474  ''' Some nodes (e.g. Schedule and Container) allow symbols to be
1475  scoped via an attached symbol table. This property returns the closest
1476  ScopingNode node including self.
1477 
1478  :returns: the closest ancestor ScopingNode node.
1479  :rtype: :py:class:`psyclone.psyir.node.ScopingNode`
1480 
1481  :raises SymbolError: if there is no ScopingNode ancestor.
1482 
1483  '''
1484  # These imports have to be local to this method to avoid circular
1485  # dependencies.
1486  # pylint: disable=import-outside-toplevel
1487  from psyclone.psyir.nodes.scoping_node import ScopingNode
1488  node = self.ancestor(ScopingNode, include_self=True)
1489  if node:
1490  return node
1491  raise SymbolError(
1492  f"Unable to find the scope of node '{self}' as none of its "
1493  f"ancestors are Container or Schedule nodes.")
1494 

References psyclone.psyir.nodes.node.Node.ancestor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ siblings()

def psyclone.psyir.nodes.node.Node.siblings (   self)
:returns: list of sibling nodes, including self.
:rtype: List[:py:class:`psyclone.psyir.nodes.Node`]

Definition at line 961 of file node.py.

961  def siblings(self):
962  '''
963  :returns: list of sibling nodes, including self.
964  :rtype: List[:py:class:`psyclone.psyir.nodes.Node`]
965  '''
966  parent = self.parent
967  return [self] if parent is None else parent.children
968 

References psyclone.f2pygen.BaseGen.parent(), and psyclone.psyir.nodes.node.Node.parent().

Here is the call graph for this function:

◆ update_signal()

def psyclone.psyir.nodes.node.Node.update_signal (   self)
Called whenever there is a change in the PSyIR tree below this node.
It is responsible for ensuring that this method does not get called
recursively and then calls the _update_node() method of the current
node (which is the only part that subclasses should specialise).
Finally, it propagates the update signal up to the parent node
(if any).

Definition at line 1666 of file node.py.

1666  def update_signal(self):
1667  '''
1668  Called whenever there is a change in the PSyIR tree below this node.
1669  It is responsible for ensuring that this method does not get called
1670  recursively and then calls the _update_node() method of the current
1671  node (which is the only part that subclasses should specialise).
1672  Finally, it propagates the update signal up to the parent node
1673  (if any).
1674 
1675  '''
1676  # Ensure that update_signal does not get called recursively.
1677  if self._disable_tree_update:
1678  return
1679 
1680  # Perform the update, disabling the recursive call of this routine on
1681  # this node.
1682  self._disable_tree_update = True
1683  self._update_node()
1684  self._disable_tree_update = False
1685 
1686  # Propagate the signal up the tree.
1687  if self._parent:
1688  self._parent.update_signal()
1689 

References psyclone.psyir.nodes.node.Node._disable_tree_update, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.GridArg._parent, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.FieldArg._parent, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.ScalarArg._parent, psyclone.domain.lfric.lfric_kern.LFRicKern._parent, psyclone.f2pygen.BaseGen._parent, psyclone.psyir.nodes.node.Node._parent, psyclone.psyir.nodes.acc_directives.ACCDataDirective._update_node(), and psyclone.psyir.nodes.node.Node._update_node().

Here is the call graph for this function:

◆ validate_global_constraints()

def psyclone.psyir.nodes.node.Node.validate_global_constraints (   self)
 Validates this Node in the context of the whole PSyIR tree.
Although there are validation checks for the parent<->child
relationships, there are other constraints that can only be
checked once the tree is complete and all transformations have
been applied. (One example is that an OMP Do directive must be
within the scope of an OMP Parallel directive.)

By default, this routine does nothing. It must be overridden
appropriately in any sub-classes to which constraints apply.
If an error is found then a GenerationError should be raised.

Reimplemented in psyclone.psyir.nodes.omp_task_directive.OMPTaskDirective, psyclone.psyir.nodes.omp_directives.OMPSimdDirective, psyclone.psyir.nodes.omp_directives.OMPAtomicDirective, psyclone.psyir.nodes.omp_directives.OMPLoopDirective, psyclone.psyir.nodes.omp_directives.OMPParallelDoDirective, psyclone.psyir.nodes.omp_directives.OMPDoDirective, psyclone.psyir.nodes.omp_directives.OMPTaskloopDirective, psyclone.psyir.nodes.omp_directives.OMPParallelDirective, psyclone.psyir.nodes.omp_directives.OMPSerialDirective, psyclone.psyir.nodes.omp_directives.OMPTaskwaitDirective, psyclone.psyir.nodes.omp_directives.OMPDeclareTargetDirective, psyclone.psyir.nodes.acc_directives.ACCAtomicDirective, psyclone.psyir.nodes.acc_directives.ACCLoopDirective, and psyclone.psyir.nodes.acc_directives.ACCRegionDirective.

Definition at line 1605 of file node.py.

1605  def validate_global_constraints(self):
1606  ''' Validates this Node in the context of the whole PSyIR tree.
1607  Although there are validation checks for the parent<->child
1608  relationships, there are other constraints that can only be
1609  checked once the tree is complete and all transformations have
1610  been applied. (One example is that an OMP Do directive must be
1611  within the scope of an OMP Parallel directive.)
1612 
1613  By default, this routine does nothing. It must be overridden
1614  appropriately in any sub-classes to which constraints apply.
1615  If an error is found then a GenerationError should be raised.
1616 
1617  '''
1618 
Here is the caller graph for this function:

◆ view()

def psyclone.psyir.nodes.node.Node.view (   self,
  depth = 0,
  colour = True,
  indent = "    ",
  _index = None 
)
Output a human readable description of the current node and all of
its descendents as a string.

:param int depth: depth of the tree hierarchy for output \
    text. Defaults to 0.
:param bool colour: whether to include colour coding in the \
    output. Defaults to True.
:param str indent: the indent to apply as the depth \
    increases. Defaults to 4 spaces.
:param int _index: the position of this node wrt its siblings \
    or None. Defaults to None.

:returns: a representation of this node and its descendents.
:rtype: str

:raises TypeError: if one of the arguments is the wrong type.
:raises ValueError: if the depth argument is negative.

Definition at line 854 of file node.py.

854  def view(self, depth=0, colour=True, indent=" ", _index=None):
855  '''Output a human readable description of the current node and all of
856  its descendents as a string.
857 
858  :param int depth: depth of the tree hierarchy for output \
859  text. Defaults to 0.
860  :param bool colour: whether to include colour coding in the \
861  output. Defaults to True.
862  :param str indent: the indent to apply as the depth \
863  increases. Defaults to 4 spaces.
864  :param int _index: the position of this node wrt its siblings \
865  or None. Defaults to None.
866 
867  :returns: a representation of this node and its descendents.
868  :rtype: str
869 
870  :raises TypeError: if one of the arguments is the wrong type.
871  :raises ValueError: if the depth argument is negative.
872 
873  '''
874  # Avoid circular import
875  # pylint: disable=import-outside-toplevel
876  from psyclone.psyir.nodes import Schedule
877 
878  if not isinstance(depth, int):
879  raise TypeError(
880  f"depth argument should be an int but found "
881  f"{type(depth).__name__}.")
882  if depth < 0:
883  raise ValueError(
884  f"depth argument should be a positive integer but "
885  f"found {depth}.")
886  if not isinstance(colour, bool):
887  raise TypeError(
888  f"colour argument should be a bool but found "
889  f"{type(colour).__name__}.")
890  if not isinstance(indent, str):
891  raise TypeError(
892  f"indent argument should be a str but found "
893  f"{type(indent).__name__}.")
894 
895  full_indent = depth*indent
896  description = self.node_str(colour=colour)
897  if not isinstance(self.parent, Schedule) or _index is None:
898  result = f"{full_indent}{description}\n"
899  else:
900  result = f"{full_indent}{_index}: {description}\n"
901  children_result_list = []
902  for idx, node in enumerate(self._children):
903  children_result_list.append(
904  node.view(
905  depth=depth + 1, _index=idx, colour=colour, indent=indent))
906  result = result + "".join(children_result_list)
907  return result
908 

References psyclone.f2pygen.BaseGen._children, psyclone.psyir.nodes.node.Node._children, psyclone.psyir.nodes.omp_directives.OMPParallelDirective._children, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall.node_str(), psyclone.domain.common.psylayer.psyloop.PSyLoop.node_str(), psyclone.domain.lfric.lfric_invoke_schedule.LFRicInvokeSchedule.node_str(), psyclone.domain.lfric.lfric_loop.LFRicLoop.node_str(), psyclone.dynamo0p3.LFRicHaloExchange.node_str(), psyclone.psyGen.InvokeSchedule.node_str(), psyclone.psyGen.GlobalSum.node_str(), psyclone.psyGen.HaloExchange.node_str(), psyclone.psyGen.Kern.node_str(), psyclone.psyGen.CodedKern.node_str(), psyclone.psyGen.InlinedKern.node_str(), psyclone.psyir.nodes.acc_directives.ACCLoopDirective.node_str(), psyclone.psyir.nodes.call.Call.node_str(), psyclone.psyir.nodes.codeblock.CodeBlock.node_str(), psyclone.psyir.nodes.container.Container.node_str(), psyclone.psyir.nodes.file_container.FileContainer.node_str(), psyclone.psyir.nodes.literal.Literal.node_str(), psyclone.psyir.nodes.loop.Loop.node_str(), psyclone.psyir.nodes.member.Member.node_str(), psyclone.psyir.nodes.node.Node.node_str(), psyclone.psyir.nodes.omp_clauses.OMPDefaultClause.node_str(), psyclone.psyir.nodes.omp_clauses.OMPScheduleClause.node_str(), psyclone.psyir.nodes.omp_clauses.OMPDependClause.node_str(), psyclone.psyir.nodes.omp_directives.OMPDoDirective.node_str(), psyclone.psyir.nodes.omp_directives.OMPLoopDirective.node_str(), psyclone.psyir.nodes.operation.Operation.node_str(), psyclone.psyir.nodes.reference.Reference.node_str(), psyclone.psyir.nodes.routine.Routine.node_str(), psyclone.f2pygen.BaseGen.parent(), and psyclone.psyir.nodes.node.Node.parent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ walk()

def psyclone.psyir.nodes.node.Node.walk (   self,
  my_type,
  stop_type = None,
  depth = None 
)
 Recurse through the PSyIR tree and return all objects that are
an instance of 'my_type', which is either a single class or a tuple
of classes. In the latter case all nodes are returned that are
instances of any classes in the tuple. The recursion into the tree
is stopped if an instance of 'stop_type' (which is either a single
class or a tuple of classes) is found. This can be used to avoid
analysing e.g. inlined kernels, or as performance optimisation to
reduce the number of recursive calls. The recursion into the tree is
also stopped if the (optional) 'depth' level is reached.

:param my_type: the class(es) for which the instances are collected.
:type my_type: type | Tuple[type, ...]
:param stop_type: class(es) at which recursion is halted (optional).
:type stop_type: Optional[type | Tuple[type, ...]]
:param depth: the depth value the instances must have (optional).
:type depth: Optional[int]

:returns: list with all nodes that are instances of my_type \
          starting at and including this node.
:rtype: List[:py:class:`psyclone.psyir.nodes.Node`]

Definition at line 1075 of file node.py.

1075  def walk(self, my_type, stop_type=None, depth=None):
1076  ''' Recurse through the PSyIR tree and return all objects that are
1077  an instance of 'my_type', which is either a single class or a tuple
1078  of classes. In the latter case all nodes are returned that are
1079  instances of any classes in the tuple. The recursion into the tree
1080  is stopped if an instance of 'stop_type' (which is either a single
1081  class or a tuple of classes) is found. This can be used to avoid
1082  analysing e.g. inlined kernels, or as performance optimisation to
1083  reduce the number of recursive calls. The recursion into the tree is
1084  also stopped if the (optional) 'depth' level is reached.
1085 
1086  :param my_type: the class(es) for which the instances are collected.
1087  :type my_type: type | Tuple[type, ...]
1088  :param stop_type: class(es) at which recursion is halted (optional).
1089  :type stop_type: Optional[type | Tuple[type, ...]]
1090  :param depth: the depth value the instances must have (optional).
1091  :type depth: Optional[int]
1092 
1093  :returns: list with all nodes that are instances of my_type \
1094  starting at and including this node.
1095  :rtype: List[:py:class:`psyclone.psyir.nodes.Node`]
1096 
1097  '''
1098  local_list = []
1099  if isinstance(self, my_type) and depth in [None, self.depth]:
1100  local_list.append(self)
1101 
1102  # Stop recursion further into the tree if an instance of a class
1103  # listed in stop_type is found.
1104  if stop_type and isinstance(self, stop_type):
1105  return local_list
1106 
1107  # Stop recursion further into the tree if a depth level has been
1108  # specified and it is reached.
1109  if depth is not None and self.depth >= depth:
1110  return local_list
1111 
1112  for child in self.children:
1113  local_list += child.walk(my_type, stop_type, depth=depth)
1114  return local_list
1115 

References psyclone.f2pygen.BaseGen.children(), psyclone.psyGen.InlinedKern.children, psyclone.psyir.nodes.node.Node.children(), psyclone.psyir.nodes.node.Node.depth(), and psyclone.gocean1p0.GOStencil.depth().

Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following file: