Reference Guide  2.5.0
psyclone.psyGen.Invoke Class Reference
Inheritance diagram for psyclone.psyGen.Invoke:

Public Member Functions

def __init__ (self, alg_invocation, idx, schedule_class, invokes, reserved_names=None)
 
def __str__ (self)
 
def invokes (self)
 
def name (self)
 
def alg_unique_args (self)
 
def psy_unique_vars (self)
 
def psy_unique_var_names (self)
 
def schedule (self)
 
def schedule (self, obj)
 
def unique_declarations (self, argument_types, access=None, intrinsic_type=None)
 
def first_access (self, arg_name)
 
def unique_declns_by_intent (self, argument_types, intrinsic_type=None)
 
def gen (self)
 
def gen_code (self, parent)
 

Detailed Description

Manage an individual invoke call.

:param alg_invocation: metadata from the parsed code capturing \
                       information for this Invoke instance.
:type alg_invocation: :py:class:`psyclone.parse.algorithm.InvokeCall`
:param int idx: position/index of this invoke call in the subroutine. \
                If not None, this number is added to the name ("invoke\_").
:param schedule_class: the schedule class to create for this invoke.
:type schedule_class: :py:class:`psyclone.psyGen.InvokeSchedule`
:param invokes: the Invokes instance that contains this Invoke \
                instance.
:type invokes: :py:class:`psyclone.psyGen.Invokes`
:param reserved_names: optional list of reserved names, i.e. names that \
                       should not be used e.g. as a PSyclone-created \
                       variable name.
:type reserved_names: list of str

Definition at line 367 of file psyGen.py.

Constructor & Destructor Documentation

◆ __init__()

def psyclone.psyGen.Invoke.__init__ (   self,
  alg_invocation,
  idx,
  schedule_class,
  invokes,
  reserved_names = None 
)
Construct an invoke object.

Definition at line 386 of file psyGen.py.

387  reserved_names=None):
388  '''Construct an invoke object.'''
389 
390  self._invokes = invokes
391  self._name = "invoke"
392  self._alg_unique_args = []
393 
394  if alg_invocation is None and idx is None:
395  return
396 
397  # create a name for the call if one does not already exist
398  if alg_invocation.name is not None:
399  # In Python2 unicode strings must be converted to str()
400  self._name = str(alg_invocation.name)
401  elif len(alg_invocation.kcalls) == 1 and \
402  alg_invocation.kcalls[0].type == "kernelCall":
403  # use the name of the kernel call with the position appended.
404  # Appended position is needed in case we have two separate invokes
405  # in the same algorithm code containing the same (single) kernel
406  self._name = "invoke_" + str(idx) + "_" + \
407  alg_invocation.kcalls[0].ktype.name
408  else:
409  # use the position of the invoke
410  self._name = "invoke_" + str(idx)
411 
412  if not reserved_names:
413  reserved_names = []
414 
415  # Get a reference to the parent container, if any
416  container = None
417  if self.invokes:
418  container = self.invokes.psy.container
419 
420  # create the schedule
421  self._schedule = schedule_class(self._name, alg_invocation.kcalls,
422  reserved_names, parent=container)
423 
424  # Add the new Schedule to the top-level PSy Container
425  if container:
426  container.addchild(self._schedule)
427 
428  # let the schedule have access to me
429  self._schedule.invoke = self
430 
431  # extract the argument list for the algorithm call and psy
432  # layer subroutine.
433  self._alg_unique_args = []
434  self._psy_unique_vars = []
435  tmp_arg_names = []
436  for call in self.schedule.kernels():
437  for arg in call.arguments.args:
438  if arg.text is not None:
439  if arg.text not in self._alg_unique_args:
440  self._alg_unique_args.append(arg.text)
441  if arg.name not in tmp_arg_names:
442  tmp_arg_names.append(arg.name)
443  self._psy_unique_vars.append(arg)
444  else:
445  # literals have no name
446  pass
447 
448  # work out the unique dofs required in this subroutine
449  self._dofs = {}
450  for kern_call in self._schedule.coded_kernels():
451  dofs = kern_call.arguments.dofs
452  for dof in dofs:
453  if dof not in self._dofs:
454  # Only keep the first occurrence for the moment. We will
455  # need to change this logic at some point as we need to
456  # cope with writes determining the dofs that are used.
457  self._dofs[dof] = [kern_call, dofs[dof][0]]
458 

References psyclone.psyGen.Invoke._alg_unique_args, psyclone.dynamo0p3.DynKernelArguments._dofs, psyclone.gocean1p0.GOKernelArguments._dofs, psyclone.psyGen.Invoke._dofs, psyclone.dynamo0p3.DynamoPSy._invokes, psyclone.gocean1p0.GOPSy._invokes, psyclone.nemo.NemoInvoke._invokes, psyclone.nemo.NemoPSy._invokes, psyclone.psyGen.PSy._invokes, psyclone.psyGen.Invoke._invokes, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._name, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata._name, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.GridArg._name, psyclone.domain.lfric.kernel.lfric_kernel_metadata.LFRicKernelMetadata._name, psyclone.dynamo0p3.DynFuncDescriptor03._name, psyclone.expression.NamedArg._name, psyclone.gocean1p0.GOKernelGridArgument._name, psyclone.gocean1p0.GOStencil._name, psyclone.nemo.NemoInvoke._name, psyclone.nemo.NemoPSy._name, psyclone.parse.algorithm.FileInfo._name, psyclone.parse.algorithm.InvokeCall._name, psyclone.parse.kernel.KernelProcedure._name, psyclone.parse.kernel.KernelType._name, psyclone.parse.module_info.ModuleInfo._name, psyclone.psyGen.PSy._name, psyclone.psyGen.Invoke._name, psyclone.psyGen.Kern._name, psyclone.psyGen.Argument._name, psyclone.psyir.nodes.container.Container._name, psyclone.psyir.nodes.routine.Routine._name, psyclone.psyir.symbols.symbol.Symbol._name, psyclone.psyGen.Invoke._psy_unique_vars, psyclone.domain.lfric.lfric_invoke.LFRicInvoke._schedule, psyclone.dynamo0p3.DynMeshes._schedule, psyclone.gocean1p0.GOInvoke._schedule, psyclone.nemo.NemoInvoke._schedule, psyclone.psyGen.Invoke._schedule, psyclone.psyir.nodes.omp_clauses.OMPScheduleClause._schedule, psyclone.psyGen.PSy.invokes(), psyclone.psyGen.Invoke.invokes(), psyclone.psyGen.Invoke.schedule(), and psyclone.psyir.nodes.omp_clauses.OMPScheduleClause.schedule.

Here is the call graph for this function:

Member Function Documentation

◆ first_access()

def psyclone.psyGen.Invoke.first_access (   self,
  arg_name 
)
 Returns the first argument with the specified name passed to
a kernel in our schedule 

Definition at line 561 of file psyGen.py.

561  def first_access(self, arg_name):
562  ''' Returns the first argument with the specified name passed to
563  a kernel in our schedule '''
564  for call in self.schedule.kernels():
565  for arg in call.arguments.args:
566  if arg.text is not None:
567  if arg.declaration_name == arg_name:
568  return arg
569  raise GenerationError(f"Failed to find any kernel argument with name "
570  f"'{arg_name}'")
571 

References psyclone.psyGen.Invoke.schedule(), and psyclone.psyir.nodes.omp_clauses.OMPScheduleClause.schedule.

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

◆ gen_code()

def psyclone.psyGen.Invoke.gen_code (   self,
  parent 
)
Generates invocation code (the subroutine called by the associated
invoke call in the algorithm layer). This consists of the PSy
invocation subroutine and the declaration of its arguments.

:param parent: the node in the generated AST to which to add content.
:type parent: :py:class:`psyclone.f2pygen.ModuleGen`

Reimplemented in psyclone.gocean1p0.GOInvoke, and psyclone.domain.lfric.lfric_invoke.LFRicInvoke.

Definition at line 653 of file psyGen.py.

653  def gen_code(self, parent):
654  '''
655  Generates invocation code (the subroutine called by the associated
656  invoke call in the algorithm layer). This consists of the PSy
657  invocation subroutine and the declaration of its arguments.
658 
659  :param parent: the node in the generated AST to which to add content.
660  :type parent: :py:class:`psyclone.f2pygen.ModuleGen`
661 
662  '''
663 
664 
Here is the caller graph for this function:

◆ invokes()

def psyclone.psyGen.Invoke.invokes (   self)
:returns: the Invokes instance that contains this instance.
:rtype: :py:class`psyclone.psyGen.Invokes`

Definition at line 464 of file psyGen.py.

464  def invokes(self):
465  '''
466  :returns: the Invokes instance that contains this instance.
467  :rtype: :py:class`psyclone.psyGen.Invokes`
468 
469  '''
470  return self._invokes
471 

References psyclone.psyGen.Invoke._alg_unique_args, psyclone.dynamo0p3.DynamoPSy._invokes, psyclone.gocean1p0.GOPSy._invokes, psyclone.nemo.NemoInvoke._invokes, psyclone.nemo.NemoPSy._invokes, psyclone.psyGen.PSy._invokes, psyclone.psyGen.Invoke._invokes, psyclone.domain.common.algorithm.psyir.AlgorithmInvokeCall._name, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata._name, psyclone.domain.gocean.kernel.psyir.GOceanKernelMetadata.GridArg._name, psyclone.domain.lfric.kernel.lfric_kernel_metadata.LFRicKernelMetadata._name, psyclone.dynamo0p3.DynFuncDescriptor03._name, psyclone.expression.NamedArg._name, psyclone.gocean1p0.GOKernelGridArgument._name, psyclone.gocean1p0.GOStencil._name, psyclone.nemo.NemoInvoke._name, psyclone.nemo.NemoPSy._name, psyclone.parse.algorithm.FileInfo._name, psyclone.parse.algorithm.InvokeCall._name, psyclone.parse.kernel.KernelProcedure._name, psyclone.parse.kernel.KernelType._name, psyclone.parse.module_info.ModuleInfo._name, psyclone.psyGen.PSy._name, psyclone.psyGen.Invoke._name, psyclone.psyGen.Kern._name, psyclone.psyGen.Argument._name, psyclone.psyir.nodes.container.Container._name, psyclone.psyir.nodes.routine.Routine._name, psyclone.psyir.symbols.symbol.Symbol._name, psyclone.psyGen.Invoke._psy_unique_vars, psyclone.domain.lfric.lfric_invoke.LFRicInvoke._schedule, psyclone.dynamo0p3.DynMeshes._schedule, psyclone.gocean1p0.GOInvoke._schedule, psyclone.nemo.NemoInvoke._schedule, psyclone.psyGen.Invoke._schedule, and psyclone.psyir.nodes.omp_clauses.OMPScheduleClause._schedule.

Here is the caller graph for this function:

◆ unique_declarations()

def psyclone.psyGen.Invoke.unique_declarations (   self,
  argument_types,
  access = None,
  intrinsic_type = None 
)
Returns a list of all required declarations for the specified
API argument types. If access is supplied (e.g. "write") then
only declarations with that access are returned. If an intrinsic
type is supplied then only declarations with that intrinsic type
are returned.

:param argument_types: the types of the kernel argument for the \
                       particular API.
:type argument_types: list of str
:param access: optional AccessType that the declaration should have.
:type access: :py:class:`psyclone.core.access_type.AccessType`
:param intrinsic_type: optional intrinsic type of argument data.
:type intrinsic_type: str

:returns: a list of all declared kernel arguments.
:rtype: list of :py:class:`psyclone.psyGen.KernelArgument`

:raises InternalError: if at least one kernel argument type is \
                       not valid for the particular API.
:raises InternalError: if an invalid access is specified.
:raises InternalError: if an invalid intrinsic type is specified.

Definition at line 499 of file psyGen.py.

500  intrinsic_type=None):
501  '''
502  Returns a list of all required declarations for the specified
503  API argument types. If access is supplied (e.g. "write") then
504  only declarations with that access are returned. If an intrinsic
505  type is supplied then only declarations with that intrinsic type
506  are returned.
507 
508  :param argument_types: the types of the kernel argument for the \
509  particular API.
510  :type argument_types: list of str
511  :param access: optional AccessType that the declaration should have.
512  :type access: :py:class:`psyclone.core.access_type.AccessType`
513  :param intrinsic_type: optional intrinsic type of argument data.
514  :type intrinsic_type: str
515 
516  :returns: a list of all declared kernel arguments.
517  :rtype: list of :py:class:`psyclone.psyGen.KernelArgument`
518 
519  :raises InternalError: if at least one kernel argument type is \
520  not valid for the particular API.
521  :raises InternalError: if an invalid access is specified.
522  :raises InternalError: if an invalid intrinsic type is specified.
523 
524  '''
525  # First check for invalid argument types, access and intrinsic type
526  const = Config.get().api_conf().get_constants()
527  if any(argtype not in const.VALID_ARG_TYPE_NAMES for
528  argtype in argument_types):
529  raise InternalError(
530  f"Invoke.unique_declarations() called with at least one "
531  f"invalid argument type. Expected one of "
532  f"{const.VALID_ARG_TYPE_NAMES} but found {argument_types}.")
533 
534  if access and not isinstance(access, AccessType):
535  raise InternalError(
536  f"Invoke.unique_declarations() called with an invalid "
537  f"access type. Type is '{access}' instead of AccessType.")
538 
539  if (intrinsic_type and intrinsic_type not in
540  const.VALID_INTRINSIC_TYPES):
541  raise InternalError(
542  f"Invoke.unique_declarations() called with an invalid "
543  f"intrinsic argument data type. Expected one of "
544  f"{const.VALID_INTRINSIC_TYPES} but found '{intrinsic_type}'.")
545 
546  # Initialise dictionary of kernel arguments to get the
547  # argument list from
548  declarations = OrderedDict()
549  # Find unique kernel arguments using their declaration names
550  for call in self.schedule.kernels():
551  for arg in call.arguments.args:
552  if not intrinsic_type or arg.intrinsic_type == intrinsic_type:
553  if not access or arg.access == access:
554  if arg.text is not None:
555  if arg.argument_type in argument_types:
556  test_name = arg.declaration_name
557  if test_name not in declarations:
558  declarations[test_name] = arg
559  return list(declarations.values())
560 

References psyclone.psyGen.Invoke.schedule(), and psyclone.psyir.nodes.omp_clauses.OMPScheduleClause.schedule.

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

◆ unique_declns_by_intent()

def psyclone.psyGen.Invoke.unique_declns_by_intent (   self,
  argument_types,
  intrinsic_type = None 
)
Returns a dictionary listing all required declarations for each
type of intent ('inout', 'out' and 'in').

:param argument_types: the types of the kernel argument for the \
                       particular API for which the intent is required.
:type argument_types: list of str
:param intrinsic_type: optional intrinsic type of argument data.
:type intrinsic_type: str

:returns: dictionary containing 'intent' keys holding the kernel \
          arguments as values for each type of intent.
:rtype: dict of :py:class:`psyclone.psyGen.KernelArgument`

:raises InternalError: if at least one kernel argument type is \
                       not valid for the particular API.
:raises InternalError: if an invalid intrinsic type is specified.

Definition at line 572 of file psyGen.py.

572  def unique_declns_by_intent(self, argument_types, intrinsic_type=None):
573  '''
574  Returns a dictionary listing all required declarations for each
575  type of intent ('inout', 'out' and 'in').
576 
577  :param argument_types: the types of the kernel argument for the \
578  particular API for which the intent is required.
579  :type argument_types: list of str
580  :param intrinsic_type: optional intrinsic type of argument data.
581  :type intrinsic_type: str
582 
583  :returns: dictionary containing 'intent' keys holding the kernel \
584  arguments as values for each type of intent.
585  :rtype: dict of :py:class:`psyclone.psyGen.KernelArgument`
586 
587  :raises InternalError: if at least one kernel argument type is \
588  not valid for the particular API.
589  :raises InternalError: if an invalid intrinsic type is specified.
590 
591  '''
592  # First check for invalid argument types and intrinsic type
593  const = Config.get().api_conf().get_constants()
594  if any(argtype not in const.VALID_ARG_TYPE_NAMES for
595  argtype in argument_types):
596  raise InternalError(
597  f"Invoke.unique_declns_by_intent() called with at least one "
598  f"invalid argument type. Expected one of "
599  f"{const.VALID_ARG_TYPE_NAMES} but found {argument_types}.")
600 
601  if (intrinsic_type and intrinsic_type not in
602  const.VALID_INTRINSIC_TYPES):
603  raise InternalError(
604  f"Invoke.unique_declns_by_intent() called with an invalid "
605  f"intrinsic argument data type. Expected one of "
606  f"{const.VALID_INTRINSIC_TYPES} but found '{intrinsic_type}'.")
607 
608  # We will return a dictionary containing as many lists
609  # as there are types of intent
610  declns = {}
611  for intent in FORTRAN_INTENT_NAMES:
612  declns[intent] = []
613 
614  for arg in self.unique_declarations(argument_types,
615  intrinsic_type=intrinsic_type):
616  first_arg = self.first_access(arg.declaration_name)
617  if first_arg.access in [AccessType.WRITE, AccessType.SUM]:
618  # If the first access is a write then the intent is
619  # out irrespective of any other accesses. Note,
620  # sum_args behave as if they are write_args from the
621  # PSy-layer's perspective.
622  declns["out"].append(arg)
623  continue
624  # if all accesses are read, then the intent is in,
625  # otherwise the intent is inout (as we have already
626  # dealt with intent out).
627  read_only = True
628  for call in self.schedule.kernels():
629  for tmp_arg in call.arguments.args:
630  if tmp_arg.text is not None and \
631  tmp_arg.declaration_name == arg.declaration_name:
632  if tmp_arg.access != AccessType.READ:
633  # readwrite_args behave in the
634  # same way as inc_args from the
635  # perspective of intents
636  read_only = False
637  break
638  if not read_only:
639  break
640  if read_only:
641  declns["in"].append(arg)
642  else:
643  declns["inout"].append(arg)
644  return declns
645 

References psyclone.psyGen.Invoke.first_access(), psyclone.psyir.nodes.acc_directives.ACCDataDirective.gen_code(), psyclone.domain.lfric.lfric_invoke.LFRicInvoke.gen_code(), psyclone.domain.lfric.lfric_loop.LFRicLoop.gen_code(), psyclone.dynamo0p3.DynGlobalSum.gen_code(), psyclone.dynamo0p3.LFRicHaloExchange.gen_code(), psyclone.gocean1p0.GOInvokes.gen_code(), psyclone.gocean1p0.GOInvoke.gen_code(), psyclone.gocean1p0.GOLoop.gen_code(), psyclone.psyGen.Invokes.gen_code(), psyclone.psyGen.Invoke.gen_code(), psyclone.psyGen.InvokeSchedule.gen_code(), psyclone.psyGen.Kern.gen_code(), psyclone.psyir.nodes.acc_directives.ACCRoutineDirective.gen_code(), psyclone.psyir.nodes.acc_directives.ACCEnterDataDirective.gen_code(), psyclone.psyir.nodes.acc_directives.ACCParallelDirective.gen_code(), psyclone.psyir.nodes.acc_directives.ACCLoopDirective.gen_code(), psyclone.psyir.nodes.acc_directives.ACCKernelsDirective.gen_code(), psyclone.psyir.nodes.assignment.Assignment.gen_code(), psyclone.psyir.nodes.extract_node.ExtractNode.gen_code(), psyclone.psyir.nodes.loop.Loop.gen_code(), psyclone.psyir.nodes.omp_directives.OMPDeclareTargetDirective.gen_code(), psyclone.psyir.nodes.omp_directives.OMPTaskwaitDirective.gen_code(), psyclone.psyir.nodes.omp_directives.OMPSingleDirective.gen_code(), psyclone.psyir.nodes.omp_directives.OMPMasterDirective.gen_code(), psyclone.psyir.nodes.omp_directives.OMPParallelDirective.gen_code(), psyclone.psyir.nodes.omp_directives.OMPTaskloopDirective.gen_code(), psyclone.psyir.nodes.omp_directives.OMPDoDirective.gen_code(), psyclone.psyir.nodes.omp_directives.OMPParallelDoDirective.gen_code(), psyclone.psyir.nodes.schedule.Schedule.gen_code(), psyclone.psyir.nodes.psy_data_node.PSyDataNode.gen_code(), psyclone.psyGen.Invoke.schedule(), psyclone.psyir.nodes.omp_clauses.OMPScheduleClause.schedule, and psyclone.psyGen.Invoke.unique_declarations().

Here is the call graph for this function:

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