psyclone.domain.nemo.transformations

Transformations module for NEMO.

Submodules

Classes

class psyclone.domain.nemo.transformations.CreateNemoInvokeScheduleTrans

Transform a generic PSyIR Routine into a NEMO InvokeSchedule. For example:

>>> from psyclone.psyir.frontend.fortran import FortranReader
>>> from psyclone.psyir.nodes import Loop
>>> from psyclone.domain.nemo.transformations import     CreateNemoInvokeScheduleTrans
>>> code = '''
... subroutine sub()
...   integer :: ji
...   real :: tmp(10)
...   do ji=1, 10
...     tmp(ji) = 2.0*ji
...   end do
... end subroutine sub'''
>>> psyir = FortranReader().psyir_from_source(code)
>>> loop = psyir.walk(Loop)[0]
>>> trans = CreateNemoInvokeScheduleTrans()
>>> trans.apply(psyir.children[0])
>>> print(psyir.view(colour=False))
FileContainer[]
    NemoInvokeSchedule[invoke='sub']
        0: Loop[variable='ji']
            Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
            Literal[value:'10', Scalar<INTEGER, UNDEFINED>]
            Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
            Schedule[]
                0: Assignment[]
                    ArrayReference[name:'tmp']
                        Reference[name:'ji']
                    BinaryOperation[operator:'MUL']
                        Literal[value:'2.0', Scalar<REAL, UNDEFINED>]
                        Reference[name:'ji']

The root node of this example has been transformed from a Routine into a NemoInvokeSchedule.

Inheritance

Inheritance diagram of CreateNemoInvokeScheduleTrans
apply(node, options=None)

Takes a generic PSyIR Routine and replaces it with a NemoInvokeSchedule (in-place). Note that this may mean replacing the top-level node itself and therefore this routine returns the root of the modified tree.

Parameters:
  • node (psyclone.psyir.nodes.Routine) – the routine node to be transformed.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

property name
Returns:

the name of the transformation.

Return type:

str

TODO #1214 remove this method.

validate(node, options=None)

Check that the supplied node is a valid target for this transformation.

Parameters:
  • node (psyclone.psyir.nodes.Node) – the target of the transformation.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

Raises:

TransformationError – if the supplied node is not a Routine.

class psyclone.domain.nemo.transformations.CreateNemoLoopTrans

Transform a generic PSyIR Loop into a NemoLoop. For example:

>>> from psyclone.psyir.frontend.fortran import FortranReader
>>> from psyclone.psyir.nodes import Loop
>>> from psyclone.domain.nemo.transformations import CreateNemoLoopTrans
>>> code = '''
... subroutine sub()
...   integer :: ji, tmp(10)
...   do ji=1, 10
...     tmp(ji) = 2*ji
...   end do
... end subroutine sub'''
>>> psyir = FortranReader().psyir_from_source(code)
>>> loops = psyir.walk(Loop)
>>> trans = CreateNemoLoopTrans()
>>> trans.apply(loops[0])
>>> print(psyir.view(colour=False))
FileContainer[]
    Routine[name:'sub']
        0: Loop[type='lon', field_space='None', it_space='None']
            Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
            Literal[value:'10', Scalar<INTEGER, UNDEFINED>]
            Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
            Schedule[]
                0: Assignment[]
                    ArrayReference[name:'tmp']
                        Reference[name:'ji']
                    BinaryOperation[operator:'MUL']
                        Literal[value:'2', Scalar<INTEGER, UNDEFINED>]
                        Reference[name:'ji']

As shown above, the resulting Schedule now contains a NemoLoop, indicated by the “type=’lon’” (for ‘longitude’) annotation for the Loop node.

Inheritance

Inheritance diagram of CreateNemoLoopTrans
apply(loop, options=None)

Takes a generic PSyIR Loop node and replaces it with a NemoLoop.

Parameters:
  • loop (psyclone.psyir.nodes.Loop) – the Loop node to be transformed.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

property name
Returns:

the name of the transformation.

Return type:

str

TODO #1214 remove this method.

validate(node, options=None)

Check that the supplied node is a valid target for this transformation.

Parameters:
  • node (psyclone.psyir.nodes.Node) – the target of the transformation.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

Raises:

TransformationError – if the supplied node is not a Routine.

class psyclone.domain.nemo.transformations.CreateNemoPSyTrans

Transform generic (language-level) PSyIR representation into a PSyclone version with specialised, NEMO-specific nodes. For example:

>>> from psyclone.psyir.frontend.fortran import FortranReader
>>> from psyclone.psyir.nodes import Loop
>>> from psyclone.domain.nemo.transformations import CreateNemoPSyTrans
>>> code = '''
... subroutine sub()
...   integer :: ji, tmp(10)
...   do ji=1, 10
...     tmp(ji) = 2*ji
...   end do
... end subroutine sub'''
>>> psyir = FortranReader().psyir_from_source(code)
>>> loop = psyir.walk(Loop)[0]
>>> trans = CreateNemoPSyTrans()
>>> trans.apply(psyir)
>>> print(psyir.view(colour=False, indent="   "))
FileContainer[]
   NemoInvokeSchedule[invoke='sub']
      0: Loop[type='lon', field_space='None', it_space='None']
         Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
         Literal[value:'10', Scalar<INTEGER, UNDEFINED>]
         Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
         Schedule[]
            0: Assignment[]
               ArrayReference[name:'tmp']
                  Reference[name:'ji']
               BinaryOperation[operator:'MUL']
                  Literal[value:'2', Scalar<INTEGER, UNDEFINED>]
                  Reference[name:'ji']

The result of this transformation is that the root Routine has been converted into a NemoInvokeSchedule, the Loop is now a NemoLoop (with type ‘lon’ [for longitude]) and the body of the loop is now an InlinedKern.

Inheritance

Inheritance diagram of CreateNemoPSyTrans
apply(psyir, options=None)

Takes generic PSyIR and replaces recognised structures with NEMO-specific PSyIR (in-place). Note that this may mean replacing the top-level node itself and therefore this routine returns the root of the modified tree.

Parameters:
  • psyir (psyclone.psyir.nodes.Node) – the root node of the PSyIR tree to process.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

property name
Returns:

the name of the transformation.

Return type:

str

TODO #1214 remove this method.

validate(node, options=None)

Check that the supplied node is a valid target for this transformation.

Parameters:
  • node (psyclone.psyir.nodes.Node) – the root of the PSyIR tree to be transformed.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

Raises:

TransformationError – if the supplied node is not a PSyIR node.

class psyclone.domain.nemo.transformations.NemoAllArrayRange2LoopTrans

Provides a transformation for all PSyIR Array Ranges in an assignment to PSyIR NemoLoops. For example:

>>> from psyclone.parse.algorithm import parse
>>> from psyclone.psyGen import PSyFactory
>>> api = "nemo"
>>> filename = "tra_adv.F90" # examples/nemo/code
>>> ast, invoke_info = parse(filename, api=api)
>>> psy = PSyFactory(api).create(invoke_info)
>>> schedule = psy.invokes.invoke_list[0].schedule
>>>
>>> from psyclone.psyir.nodes import Assignment
>>> from psyclone.domain.nemo.transformations import             NemoAllArrayRange2LoopTrans
>>>
>>> print(schedule.view())
>>> trans = NemoAllArrayRange2LoopTrans()
>>> for assignment in schedule.walk(Assignment):
>>>     trans.apply(assignment)
>>> print(schedule.view())

Inheritance

Inheritance diagram of NemoAllArrayRange2LoopTrans
apply(node, options=None)

Apply the NemoAllArrayRange2Loop transformation to the specified node if the node is an Assignment and the left-hand-side of the assignment is an Array Reference containing at least one Range node specifying an access to an array index. If this is the case then all Range nodes within array references within the assignment are replaced with references to the appropriate loop indices. The appropriate number of NemoLoop loops are also placed around the modified assignment statement.

The name of each loop index is taken from the PSyclone configuration file if a name exists for the particular array index, otherwise a new name is generated. The bounds of each loop are taken from the Range node if they are provided. If not, the loop bounds are taken from the PSyclone configuration file if a bounds value is supplied. If not, the LBOUND or UBOUND intrinsics are used as appropriate. The type of the NemoLoop is also taken from the configuration file if it is supplied for that index, otherwise it is specified as being “unknown”.

Parameters:
  • node (psyclone.psyir.nodes.Assignment) – an Assignment node.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

  • options["verbose"] (bool) – whether to print out the reason why the inner transformation was not applied. This is useful because this transfomation succeeds even if one of the inner transformations fails, and therefor the reason why the inner transformation failed is not propagated.

  • options["allow_string"] (bool) – whether to allow the transformation on a character type array range. Defaults to False.

property name
Returns:

the name of the transformation.

Return type:

str

validate(node, options=None)

Perform various checks to ensure that it is valid to apply the NemoArrayRange2LoopTrans transformation to the supplied PSyIR Node.

Parameters:
  • node (psyclone.psyir.nodes.Assignment) – the node that is being checked.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

Raises:

TransformationError – if the supplied node is not an Assignment.

class psyclone.domain.nemo.transformations.NemoArrayRange2LoopTrans

Transformation that given an assignment with an ArrayReference Range in the LHS (equivalent to an array assignment statement in Fortran), it converts it to an explicit loop doing each of the individual element assignments separately. For example:

>>> from psyclone.parse.algorithm import parse
>>> from psyclone.psyGen import PSyFactory
>>> api = "nemo"
>>> filename = "tra_adv.F90" # examples/nemo/code
>>> ast, invoke_info = parse(filename, api=api)
>>> psy = PSyFactory(api).create(invoke_info)
>>> schedule = psy.invokes.invoke_list[0].schedule
>>> print(schedule.view())
>>>
>>> from psyclone.psyir.nodes import Range
>>> from psyclone.domain.nemo.transformations import             NemoArrayRange2LoopTrans
>>> from psyclone.transformations import TransformationError
>>>
>>> trans = NemoArrayRange2LoopTrans()
>>> for my_range in reversed(schedule.walk(Range)):
>>>     try:
>>>         trans.apply(my_range)
>>>     except TransformationError:
>>>         pass
>>> print(schedule.view())

The specified Range node must be the outermost Range (specifying an access to an array index) within an Array Reference and the array reference must be on the left-hand-side of an Assignment node. This is required for correctness and if not satisfied the transformation will raise an exception.

By default the transformation will reject character arrays, though this can be overriden by setting the allow_string option to True. Note that PSyclone expresses syntax such as character(LEN=100) as UnsupportedFortranType, and this transformation will convert unknown or unsupported types to loops.

Inheritance

Inheritance diagram of NemoArrayRange2LoopTrans
apply(node, options=None)

Apply the transformation such that, given an assignment with an ArrayReference Range in the LHS (equivalent to an array assignment statement in Fortran), it converts it to an explicit loop doing each of the individual element assignments separately.

The Range node is provided to the apply method of the transformation to indicate which array index should be transformed. This can only be applied to the outermost Range of the ArrayReference.

This is currently specific to the ‘nemo’ API in that it will create NemoLoops.

Parameters:
  • node (psyclone.psyir.nodes.Range) – a Range node.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

  • options["allow_string"] (bool) – whether to allow the transformation on a character type array range. Defaults to False.

property name
Returns:

the name of the transformation as a string.

Return type:

str

validate(node, options=None)

Perform various checks to ensure that it is valid to apply the NemoArrayRange2LoopTrans transformation to the supplied PSyIR Node.

By default the validation will reject character arrays that PSyclone understand as such, though this can be overriden by setting the allow_string option to True. Note that PSyclone expresses syntax such as character(LEN=100) as UnsupportedFortranType, and this transformation will convert unknown or unsupported types to loops.

Parameters:
  • node (psyclone.psyir.nodes.Range) – the node that is being checked.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

  • options["allow_string"] (bool) – whether to allow the transformation on a character type array range. Defaults to False.

Raises:
  • TransformationError – if the node argument is not a Range, if the Range node is not part of an ArrayReference, if the Range node is not the outermost Range node of the ArrayReference or if that ArrayReference does not constitute the left hand side of an Assignment node.

  • TransformationError – if the node argument has nested array expressions with Ranges or is an invalid tree with ranges in multiple locations of a structure of arrays.

  • TransformationError – if the node argument contains a non-elemental Operation or Call.

  • TransformationError – if node contains a character type child and the allow_strings option is not set.

class psyclone.domain.nemo.transformations.NemoOuterArrayRange2LoopTrans

Provides a transformation from the outermost PSyIR ArrayReference Range to a PSyIR NemoLoop. For example:

>>> from psyclone.parse.algorithm import parse
>>> from psyclone.psyGen import PSyFactory
>>> api = "nemo"
>>> filename = "tra_adv.F90" # examples/nemo/code
>>> ast, invoke_info = parse(filename, api=api)
>>> psy = PSyFactory(api).create(invoke_info)
>>> schedule = psy.invokes.invoke_list[0].schedule
>>>
>>> from psyclone.psyir.nodes import Assignment
>>> from psyclone.domain.nemo.transformations import             NemoOuterArrayRange2LoopTrans
>>> from psyclone.transformations import TransformationError
>>>
>>> print(schedule.view())
>>> trans = NemoOuterArrayRange2LoopTrans()
>>> for assignment in schedule.walk(Assignment):
>>>     while True:
>>>         try:
>>>             trans.apply(assignment)
>>>         except TransformationError:
>>>             break
>>> print(schedule.view())

Inheritance

Inheritance diagram of NemoOuterArrayRange2LoopTrans
apply(node, options=None)

Apply the NemoOuterArrayRange2Loop transformation to the specified node if the node is an Assignment and the left-hand-side of the assignment is an Array Reference containing at least one Range node specifying an access to an array index. If this is the case then the outermost Range nodes within array references within the assignment are replaced with references to a loop index. A NemoLoop loop (with the same loop index) is also placed around the modified assignment statement.

The name of the loop index is taken from the PSyclone configuration file if a name exists for the particular array index, otherwise a new name is generated. The bounds of the loop are taken from the Range node if they are provided. If not, the loop bounds are taken from the PSyclone configuration file if bounds values are supplied. If not, the LBOUND or UBOUND intrinsics are used as appropriate. The type of the NemoLoop is also taken from the configuration file if it is supplied for that index, otherwise it is specified as being “unknown”.

Parameters:
  • node (psyclone.psyir.nodes.Assignment) – an Assignment node.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

  • options["allow_string"] (bool) – whether to allow the transformation on a character type array range. Defaults to False.

property name
Returns:

the name of the transformation.

Return type:

str

validate(node, options=None)

Perform various checks to ensure that it is valid to apply the NemoOuterArrayRange2LoopTrans transformation to the supplied PSyIR Node.

Parameters:
  • node (psyclone.psyir.nodes.Assignment) – the node that is being checked.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

Raises:

TransformationError – if the supplied node is not an Assignment node, if the Assignment node does not have an Array-type Reference node on its left hand side or if the Array-type node does not contain at least one Range node.

class psyclone.domain.nemo.transformations.NemoArrayAccess2LoopTrans

Provides a transformation to transform a constant index access to an array (i.e. one that does not contain a loop iterator) to a single trip loop. For example:

>>> from psyclone.domain.nemo.transformations import \
...     NemoArrayAccess2LoopTrans
>>> from psyclone.psyir.backend.fortran import FortranWriter
>>> from psyclone.psyir.frontend.fortran import FortranReader
>>> from psyclone.psyir.nodes import Assignment
>>> code = ("program example\n"
...         "  real a(10)\n"
...         "  a(1) = 0.0\n"
...         "end program example\n")
>>> psyir = FortranReader().psyir_from_source(code)
>>> assignment = psyir.walk(Assignment)[0]
>>> NemoArrayAccess2LoopTrans().apply(assignment.lhs.children[0])
>>> print(FortranWriter()(psyir))
program example
  real, dimension(10) :: a
  integer :: ji

  do ji = 1, 1, 1
    a(ji) = 0.0
  enddo

end program example

Inheritance

Inheritance diagram of NemoArrayAccess2LoopTrans
apply(node, options=None)

Apply the NemoArrayAccess2Loop transformation if the supplied node is an access to an array index within an Array Reference that is on the left-hand-side of an Assignment node. The access must be a scalar (i.e. not a range) and must not include a loop variable (as we are transforming a single access to a loop).

These constraints are required for correctness and an exception will be raised if they are not satisfied. If the constraints are satisfied then the array access is replaced with a loop iterator and a single trip loop.

The new loop will be placed immediately around the assignment i.e. it will not take into account any expected nesting (ji, jj, jk etc) constraints. Loop re-ordering should be performed by a separate transformation.

The name of the loop index is taken from the PSyclone configuration file if a name exists for the particular array index, otherwise a new name is generated.

Parameters:
  • node (psyclone.psyir.nodes.Node) – an array index.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

validate(node, options=None)

Perform various checks to ensure that it is valid to apply the NemoArrayAccess2LoopTrans transformation to the supplied PSyIR Node.

Parameters:
  • node (psyclone.psyir.nodes.Node) – the node that is being checked.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

class psyclone.domain.nemo.transformations.NemoAllArrayAccess2LoopTrans

Provides a transformation from a PSyIR Assignment containing constant index accesses to an array into single trip loops: For example:

>>> from psyclone.domain.nemo.transformations import \
...     NemoAllArrayAccess2LoopTrans
>>> from psyclone.psyir.backend.fortran import FortranWriter
>>> from psyclone.psyir.frontend.fortran import FortranReader
>>> from psyclone.psyir.nodes import Assignment
>>> code = ("program example\n"
...         "  real a(10,10), b(10,10)\n"
...         "  integer :: n\n"
...         "  a(1,n-1) = b(1,n-1)\n"
...         "end program example\n")
>>> psyir = FortranReader().psyir_from_source(code)
>>> assignment = psyir.walk(Assignment)[0]
>>> NemoAllArrayAccess2LoopTrans().apply(assignment)
>>> print(FortranWriter()(psyir))
program example
  real, dimension(10,10) :: a
  real, dimension(10,10) :: b
  integer :: n
  integer :: ji
  integer :: jj

  do ji = 1, 1, 1
    do jj = n - 1, n - 1, 1
      a(ji,jj) = b(ji,jj)
    enddo
  enddo

end program example

Inheritance

Inheritance diagram of NemoAllArrayAccess2LoopTrans
apply(node, options=None)

Apply the NemoAllArrayAccess2Loop transformation if the supplied node is an Assignment with an Array Reference on its left-hand-side. Each constant array index access (i.e. one not containing a loop iterator or a range) is then transformed into an iterator and the assignment placed within a single trip loop, subject to any constraints in the NemoArrayAccess2Loop transformation.

If any of the NemoAllArrayAccess2Loop constraints are not satisfied for a loop index then this transformation does nothing for that index and silently moves to the next.

Parameters:
  • node (psyclone.psyir.nodes.Assignment) – an assignment.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.

property name
Returns:

the name of the transformation as a string.

Return type:

str

validate(node, options=None)

Perform any checks to ensure that it is valid to apply the NemoAllArrayAccess2LoopTrans transformation to the supplied PSyIR Node.

Parameters:
  • node (psyclone.psyir.nodes.Node) – the node that is being checked.

  • options (Optional[Dict[str, Any]]) – a dictionary with options for transformations. No options are used in this transformation. This is an optional argument that defaults to None.