psyclone.domain.nemo.transformations
Transformations module for NEMO.
Submodules
psyclone.domain.nemo.transformations.create_nemo_invoke_schedule_trans
psyclone.domain.nemo.transformations.create_nemo_loop_trans
psyclone.domain.nemo.transformations.create_nemo_psy_trans
psyclone.domain.nemo.transformations.nemo_allarrayaccess2loop_trans
psyclone.domain.nemo.transformations.nemo_allarrayrange2loop_trans
psyclone.domain.nemo.transformations.nemo_arrayaccess2loop_trans
psyclone.domain.nemo.transformations.nemo_arrayrange2loop_trans
psyclone.domain.nemo.transformations.nemo_outerarrayrange2loop_trans
Classes
CreateNemoInvokeScheduleTrans
: Transform a generic PSyIR Routine into a NEMO InvokeSchedule.CreateNemoLoopTrans
: Transform a generic PSyIR Loop into a NemoLoop. For example:CreateNemoPSyTrans
: Transform generic (language-level) PSyIR representation into a PSycloneNemoAllArrayRange2LoopTrans
: Provides a transformation for all PSyIR Array Ranges in anNemoArrayRange2LoopTrans
: Transformation that given an assignment with an ArrayReference RangeNemoOuterArrayRange2LoopTrans
: Provides a transformation from the outermost PSyIR ArrayReferenceNemoArrayAccess2LoopTrans
: Provides a transformation to transform a constant index access toNemoAllArrayAccess2LoopTrans
: Provides a transformation from a PSyIR Assignment containing
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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.