Source code for psyclone.psyir.transformations.omp_parallel_loop_trans

# -----------------------------------------------------------------------------
# BSD 3-Clause License
#
# Copyright (c) 2017-2026, 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, 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


import logging
from typing import Iterable
from psyclone.psyir.nodes import (
    OMPParallelDoDirective, OMPReductionClause, Loop)
from psyclone.psyir.nodes.omp_directives import MAP_REDUCTION_OP_TO_OMP
from psyclone.psyir.transformations.omp_loop_trans import OMPLoopTrans
from psyclone.utils import transformation_documentation_wrapper


[docs] @transformation_documentation_wrapper(inherit=False) class OMPParallelLoopTrans(OMPLoopTrans): ''' Adds an OpenMP PARALLEL DO directive to a loop. For example: >>> from psyclone.psyir.frontend.fortran import FortranReader >>> from psyclone.psyir.backend.fortran import FortranWriter >>> psyir = FortranReader().psyir_from_source(""" ... program do_loop ... real, dimension(10) :: A ... integer i ... do i = 1, 10 ... A(i) = i ... end do ... end program do_loop ... """) >>> from psyclone.psyir.nodes import Loop >>> from psyclone.transformations import OMPParallelLoopTrans >>> trans = OMPParallelLoopTrans() >>> trans.apply(psyir.walk(Loop)[0]) >>> print(FortranWriter()(psyir)) program do_loop real, dimension(10) :: a integer :: i <BLANKLINE> !$omp parallel do default(shared) private(i) schedule(auto) do i = 1, 10, 1 a(i) = i enddo !$omp end parallel do <BLANKLINE> end program do_loop <BLANKLINE> ''' def __str__(self): return "Add an 'OpenMP PARALLEL DO' directive"
[docs] def apply(self, node: Loop, force_private: Iterable[str] = tuple(), enable_reductions: bool = False, options=None, **kwargs): ''' Apply an OMPParallelLoop Transformation to the supplied node (which must be a Loop). In the generated code this corresponds to wrapping the Loop with directives: .. code-block:: fortran !$OMP PARALLEL DO ... do ... ... end do !$OMP END PARALLEL DO :param node: the node (loop) to which to apply the transformation. :param force_private: specify a list of symbol names explicitly requested to be private. :param enable_reductions: whether to enable PSyclone to compute reduction clauses on the parallelised loop. :param options: a dictionary with options for transformations and validation. :type options: Optional[Dict[str, Any]] ''' logger = logging.getLogger(__name__) # TODO #2668 - deprecate options dictionary. local_options = options.copy() if options is not None else None reduction_ops = [] if options: enable_reductions = options.get("enable_reductions", False) if enable_reductions: local_options["reduction_ops"] = \ list(MAP_REDUCTION_OP_TO_OMP.keys()) else: if enable_reductions: # Reduction_ops isn't a supported option provided in this # Transformation's docstring, however since its in the # options for its superclass we give a warning and override # it as needed. if "reduction_ops" in kwargs: del kwargs["reduction_ops"] logger.warning( f"{self.name} overrides the provided reduction_ops " f"keyword argument to those supported by PSyclone." ) reduction_ops = list(MAP_REDUCTION_OP_TO_OMP.keys()) # reduction_ops is the argument used by the superclass to determine # whether to allow reductions, so we don't pass enable_reductions. self.validate(node, options=local_options, force_private=force_private, reduction_ops=reduction_ops, **kwargs) # keep a reference to the node's original parent and its index as these # are required and will change when we change the node's location node_parent = node.parent node_position = node.position # add our OpenMP loop directive setting its parent to the node's # parent and its children to the node directive = OMPParallelDoDirective(children=[node.detach()], omp_schedule=self.omp_schedule) # add any inferred reduction clauses to the newly introduced directive for (op, ref) in self.inferred_reduction_clauses: clause = OMPReductionClause(MAP_REDUCTION_OP_TO_OMP[op]) clause.addchild(ref) directive.addchild(clause) # add the OpenMP loop directive as a child of the node's parent node_parent.addchild(directive, index=node_position) # Add explicit private variables explicitly_private_symbols = set() for symbol_name in force_private: try: sym = node.scope.symbol_table.lookup(symbol_name) explicitly_private_symbols.add(sym) except KeyError: # This is not an error, but we will log the missed string logger.warning( "%s has been provided with the '%s' symbol name in " "the 'force_private' option, but there is no such " "symbol in this scope.", self.name, symbol_name) directive.explicitly_private_symbols.update( explicitly_private_symbols)
# For Sphinx AutoAPI documentation generation __all__ = ["OMPParallelLoopTrans"]