diff --git a/src/psyclone/domain/gocean/transformations/__init__.py b/src/psyclone/domain/gocean/transformations/__init__.py index c7b79584c3..16302e8b4f 100644 --- a/src/psyclone/domain/gocean/transformations/__init__.py +++ b/src/psyclone/domain/gocean/transformations/__init__.py @@ -53,3 +53,7 @@ import RaisePSyIR2GOceanKernTrans from psyclone.domain.gocean.transformations.\ gocean_alg_invoke_2_psy_call_trans import GOceanAlgInvoke2PSyCallTrans +from psyclone.domain.gocean.transformations.gocean_omp_loop_trans import \ + GOceanOMPLoopTrans +from psyclone.domain.gocean.transformations.gocean_omp_parallel_loop_trans \ + import GOceanOMPParallelLoopTrans diff --git a/src/psyclone/domain/gocean/transformations/gocean_omp_loop_trans.py b/src/psyclone/domain/gocean/transformations/gocean_omp_loop_trans.py new file mode 100644 index 0000000000..e2f8f03a9c --- /dev/null +++ b/src/psyclone/domain/gocean/transformations/gocean_omp_loop_trans.py @@ -0,0 +1,88 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2017-2025, Science and Technology Facilities Council. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- +# Authors R. W. Ford, A. R. Porter, S. Siso and N. Nobre, STFC Daresbury Lab +# A. B. G. Chalk and V. K. Atkinson, STFC Daresbury Lab +# J. Henrichs, Bureau of Meteorology +# Modified I. Kavcic, J. G. Wallwork, O. Brunt and L. Turner, Met Office +# S. Valat, Inria / Laboratoire Jean Kuntzmann +# M. Schreiber, Univ. Grenoble Alpes / Inria / Lab. Jean Kuntzmann +# J. Dendy, Met Office + + +from psyclone.psyir.transformations.omp_loop_trans import OMPLoopTrans +from psyclone.psyir.transformations.transformation_error import ( + TransformationError) + + +class GOceanOMPLoopTrans(OMPLoopTrans): + + ''' GOcean-specific orphan OpenMP loop transformation. Adds GOcean + specific validity checks (that the node is either an inner or outer + Loop). + + :param str omp_directive: choose which OpenMP loop directive to use. \ + Defaults to "do". + :param str omp_schedule: the OpenMP schedule to use. Must be one of \ + 'runtime', 'static', 'dynamic', 'guided' or 'auto'. Defaults to \ + 'static'. + + ''' + def __init__(self, omp_directive="do", omp_schedule="static"): + super().__init__(omp_directive=omp_directive, + omp_schedule=omp_schedule) + + def __str__(self): + return "Add the selected OpenMP loop directive to a GOcean loop" + + def validate(self, node, options=None, **kwargs): + ''' + Checks that the supplied node is a valid target for parallelisation + using OMP directives. + + :param node: the candidate loop for parallelising using OMP Do. + :type node: :py:class:`psyclone.psyir.nodes.Loop` + :param options: a dictionary with options for transformations. + :type options: Optional[Dict[str, Any]] + + :raises TransformationError: if the loop_type of the supplied Loop is \ + not "inner" or "outer". + + ''' + super().validate(node, options=options) + + # Check we are either an inner or outer loop + if node.loop_type not in ["inner", "outer"]: + raise TransformationError("Error in "+self.name+" transformation." + " The requested loop is not of type " + "inner or outer.") diff --git a/src/psyclone/domain/gocean/transformations/gocean_omp_parallel_loop_trans.py b/src/psyclone/domain/gocean/transformations/gocean_omp_parallel_loop_trans.py new file mode 100644 index 0000000000..ac5ca4add7 --- /dev/null +++ b/src/psyclone/domain/gocean/transformations/gocean_omp_parallel_loop_trans.py @@ -0,0 +1,91 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2017-2025, Science and Technology Facilities Council. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- +# Authors R. W. Ford, A. R. Porter, S. Siso and N. Nobre, STFC Daresbury Lab +# A. B. G. Chalk and V. K. Atkinson, STFC Daresbury Lab +# J. Henrichs, Bureau of Meteorology +# Modified I. Kavcic, J. G. Wallwork, O. Brunt and L. Turner, Met Office +# S. Valat, Inria / Laboratoire Jean Kuntzmann +# M. Schreiber, Univ. Grenoble Alpes / Inria / Lab. Jean Kuntzmann +# J. Dendy, Met Office + +from psyclone.psyir.transformations.omp_parallel_loop_trans import ( + OMPParallelLoopTrans) +from psyclone.psyir.transformations.transformation_error import ( + TransformationError) + + +class GOceanOMPParallelLoopTrans(OMPParallelLoopTrans): + + '''GOcean specific OpenMP Do loop transformation. Adds GOcean + specific validity checks (that supplied Loop is an inner or outer + loop). Actual transformation is done by + :py:class:`base class `. + + :param str omp_directive: choose which OpenMP loop directive to use. \ + Defaults to "do". + :param str omp_schedule: the OpenMP schedule to use. Must be one of \ + 'runtime', 'static', 'dynamic', 'guided' or 'auto'. Defaults to \ + 'static'. + + ''' + def __init__(self, omp_directive="do", omp_schedule="static"): + super().__init__(omp_directive=omp_directive, + omp_schedule=omp_schedule) + + def __str__(self): + return "Add an OpenMP Parallel Do directive to a GOcean loop" + + def apply(self, node, options=None): + ''' Perform GOcean-specific loop validity checks then call + :py:meth:`OMPParallelLoopTrans.apply`. + + :param node: a Loop node from an AST. + :type node: :py:class:`psyclone.psyir.nodes.Loop` + :param options: a dictionary with options for transformations\ + and validation. + :type options: Optional[Dict[str, Any]] + + :raises TransformationError: if the supplied node is not an inner or\ + outer loop. + + ''' + self.validate(node, options=options) + + # Check we are either an inner or outer loop + if node.loop_type not in ["inner", "outer"]: + raise TransformationError( + "Error in "+self.name+" transformation. The requested loop" + " is not of type inner or outer.") + + OMPParallelLoopTrans.apply(self, node) diff --git a/src/psyclone/tests/domain/gocean/transformations/gocean1p0_transformations_test.py b/src/psyclone/tests/domain/gocean/transformations/gocean1p0_transformations_test.py index f3421de940..e7f24ba9c8 100644 --- a/src/psyclone/tests/domain/gocean/transformations/gocean1p0_transformations_test.py +++ b/src/psyclone/tests/domain/gocean/transformations/gocean1p0_transformations_test.py @@ -51,9 +51,10 @@ from psyclone.psyir.transformations import ( LoopFuseTrans, LoopTrans, TransformationError, ACCLoopTrans) from psyclone.transformations import ( - ACCRoutineTrans, OMPParallelTrans, GOceanOMPParallelLoopTrans, - GOceanOMPLoopTrans, OMPLoopTrans, ACCParallelTrans, ACCEnterDataTrans) -from psyclone.domain.gocean.transformations import GOConstLoopBoundsTrans + ACCRoutineTrans, OMPParallelTrans, + OMPLoopTrans, ACCParallelTrans, ACCEnterDataTrans) +from psyclone.domain.gocean.transformations import ( + GOConstLoopBoundsTrans, GOceanOMPLoopTrans, GOceanOMPParallelLoopTrans) from psyclone.tests.gocean_build import GOceanBuild from psyclone.tests.utilities import count_lines, get_invoke, get_base_path diff --git a/src/psyclone/tests/domain/gocean/transformations/gocean_extract_test.py b/src/psyclone/tests/domain/gocean/transformations/gocean_extract_test.py index 77c185e73d..e19140db73 100644 --- a/src/psyclone/tests/domain/gocean/transformations/gocean_extract_test.py +++ b/src/psyclone/tests/domain/gocean/transformations/gocean_extract_test.py @@ -50,10 +50,9 @@ from psyclone.psyir.transformations import (PSyDataTrans, TransformationError, ACCLoopTrans) from psyclone.transformations import (ACCParallelTrans, ACCEnterDataTrans, - GOceanOMPLoopTrans, - GOceanOMPParallelLoopTrans, OMPParallelTrans) -from psyclone.domain.gocean.transformations import GOConstLoopBoundsTrans +from psyclone.domain.gocean.transformations import ( + GOConstLoopBoundsTrans, GOceanOMPLoopTrans, GOceanOMPParallelLoopTrans) from psyclone.tests.utilities import get_invoke # API names diff --git a/src/psyclone/tests/psyir/transformations/profile_test.py b/src/psyclone/tests/psyir/transformations/profile_test.py index 00f4a6ab2c..16e0b9e55d 100644 --- a/src/psyclone/tests/psyir/transformations/profile_test.py +++ b/src/psyclone/tests/psyir/transformations/profile_test.py @@ -55,8 +55,8 @@ from psyclone.psyir.transformations import (ACCKernelsTrans, ProfileTrans, TransformationError) from psyclone.tests.utilities import get_invoke -from psyclone.transformations import (GOceanOMPLoopTrans, - OMPParallelTrans) +from psyclone.transformations import OMPParallelTrans +from psyclone.domain.gocean.transformations import GOceanOMPLoopTrans # ----------------------------------------------------------------------------- diff --git a/src/psyclone/transformations.py b/src/psyclone/transformations.py index 808fa210e6..45359f56a6 100644 --- a/src/psyclone/transformations.py +++ b/src/psyclone/transformations.py @@ -173,52 +173,6 @@ def validate(self, node, options=None): super().validate(node, options=local_options) -class GOceanOMPParallelLoopTrans(OMPParallelLoopTrans): - - '''GOcean specific OpenMP Do loop transformation. Adds GOcean - specific validity checks (that supplied Loop is an inner or outer - loop). Actual transformation is done by - :py:class:`base class `. - - :param str omp_directive: choose which OpenMP loop directive to use. \ - Defaults to "do". - :param str omp_schedule: the OpenMP schedule to use. Must be one of \ - 'runtime', 'static', 'dynamic', 'guided' or 'auto'. Defaults to \ - 'static'. - - ''' - def __init__(self, omp_directive="do", omp_schedule="static"): - super().__init__(omp_directive=omp_directive, - omp_schedule=omp_schedule) - - def __str__(self): - return "Add an OpenMP Parallel Do directive to a GOcean loop" - - def apply(self, node, options=None): - ''' Perform GOcean-specific loop validity checks then call - :py:meth:`OMPParallelLoopTrans.apply`. - - :param node: a Loop node from an AST. - :type node: :py:class:`psyclone.psyir.nodes.Loop` - :param options: a dictionary with options for transformations\ - and validation. - :type options: Optional[Dict[str, Any]] - - :raises TransformationError: if the supplied node is not an inner or\ - outer loop. - - ''' - self.validate(node, options=options) - - # Check we are either an inner or outer loop - if node.loop_type not in ["inner", "outer"]: - raise TransformationError( - "Error in "+self.name+" transformation. The requested loop" - " is not of type inner or outer.") - - OMPParallelLoopTrans.apply(self, node) - - class LFRicOMPLoopTrans(OMPLoopTrans): ''' LFRic specific orphan OpenMP loop transformation. Adds @@ -303,49 +257,6 @@ def apply(self, node, options=None, **kwargs): super().apply(node, options) -class GOceanOMPLoopTrans(OMPLoopTrans): - - ''' GOcean-specific orphan OpenMP loop transformation. Adds GOcean - specific validity checks (that the node is either an inner or outer - Loop). - - :param str omp_directive: choose which OpenMP loop directive to use. \ - Defaults to "do". - :param str omp_schedule: the OpenMP schedule to use. Must be one of \ - 'runtime', 'static', 'dynamic', 'guided' or 'auto'. Defaults to \ - 'static'. - - ''' - def __init__(self, omp_directive="do", omp_schedule="static"): - super().__init__(omp_directive=omp_directive, - omp_schedule=omp_schedule) - - def __str__(self): - return "Add the selected OpenMP loop directive to a GOcean loop" - - def validate(self, node, options=None, **kwargs): - ''' - Checks that the supplied node is a valid target for parallelisation - using OMP directives. - - :param node: the candidate loop for parallelising using OMP Do. - :type node: :py:class:`psyclone.psyir.nodes.Loop` - :param options: a dictionary with options for transformations. - :type options: Optional[Dict[str, Any]] - - :raises TransformationError: if the loop_type of the supplied Loop is \ - not "inner" or "outer". - - ''' - super().validate(node, options=options) - - # Check we are either an inner or outer loop - if node.loop_type not in ["inner", "outer"]: - raise TransformationError("Error in "+self.name+" transformation." - " The requested loop is not of type " - "inner or outer.") - - class ColourTrans(LoopTrans): ''' Apply a colouring transformation to a loop (in order to permit a @@ -2435,8 +2346,6 @@ def __new__(cls): "LFRicOMPLoopTrans", "LFRicRedundantComputationTrans", "LFRicOMPParallelLoopTrans", - "GOceanOMPLoopTrans", - "GOceanOMPParallelLoopTrans", "KernelImportsToArguments", "MoveTrans", "OMPMasterTrans",