# -----------------------------------------------------------------------------
# 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
'''
This module provides the implementation of OMPDeclareTargetTrans
'''
from typing import Any, Optional, Union
from psyclone.psyir.nodes import OMPDeclareTargetDirective, Routine
from psyclone.psyir.transformations.callee_transformation_mixin import (
CalleeTransformationMixin)
from psyclone.psyGen import Transformation, Kern
from psyclone.psyir.transformations.mark_routine_for_gpu_mixin import (
MarkRoutineForGPUMixin)
from psyclone.utils import transformation_documentation_wrapper
[docs]
@transformation_documentation_wrapper
class OMPDeclareTargetTrans(Transformation,
MarkRoutineForGPUMixin,
CalleeTransformationMixin):
'''
Adds an OpenMP declare target directive to the specified routine.
For example:
>>> from psyclone.psyir.frontend.fortran import FortranReader
>>> from psyclone.psyir.nodes import Loop
>>> from psyclone.transformations import OMPDeclareTargetTrans
>>>
>>> tree = FortranReader().psyir_from_source("""
... subroutine my_subroutine(A)
... integer, dimension(10, 10), intent(inout) :: A
... integer :: i
... integer :: j
... do i = 1, 10
... do j = 1, 10
... A(i, j) = 0
... end do
... end do
... end subroutine
... """
>>> omptargettrans = OMPDeclareTargetTrans()
>>> omptargettrans.apply(tree.walk(Routine)[0])
will generate:
.. code-block:: fortran
subroutine my_subroutine(A)
integer, dimension(10, 10), intent(inout) :: A
integer :: i
integer :: j
!$omp declare target
do i = 1, 10
do j = 1, 10
A(i, j) = 0
end do
end do
end subroutine
'''
[docs]
def apply(self,
node: Union[Routine, Kern],
options: Optional[dict[str, Any]] = None,
force: bool = False,
device_string: str = "",
**kwargs) -> None:
''' Insert an OMPDeclareTargetDirective inside the provided routine or
associated PSyKAl kernel.
:param node: the kernel or routine which is the target of this
transformation.
:param options: a dictionary with options for transformations.
:param force: whether to allow routines with CodeBlocks to run on
the GPU.
:param device_string: provide a compiler-platform identifier.
'''
self.validate(node, options, force=force, device_string=device_string,
**kwargs)
if isinstance(node, Kern):
# Get the schedule representing the kernel subroutine
routines = node.get_callees()
else:
routines = [node]
for routine in routines:
if not any(isinstance(child, OMPDeclareTargetDirective) for
child in routine.children):
routine.children.insert(0, OMPDeclareTargetDirective())
[docs]
def validate(self,
node: Union[Kern, Routine],
options: Optional[dict[str, Any]] = None,
**kwargs) -> None:
''' Check that an OMPDeclareTargetDirective can be inserted.
:param node: the kernel or routine which is the target of this
transformation.
:param options: a dictionary with options for transformations.
'''
# TODO #2668 Depracate options dict.
if not options:
self.validate_options(**kwargs)
super().validate(node, options=options, **kwargs)
self.validate_it_can_run_on_gpu(node, options, **kwargs)
if isinstance(node, Kern):
self._check_callee_implementation_is_local(node)