Reference Guide  2.5.0
omp_task_trans.py
1 # -----------------------------------------------------------------------------
2 # BSD 3-Clause License
3 #
4 # Copyright (c) 2021-2024, Science and Technology Facilities Council.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are met:
9 #
10 # * Redistributions of source code must retain the above copyright notice, this
11 # list of conditions and the following disclaimer.
12 #
13 # * Redistributions in binary form must reproduce the above copyright notice,
14 # this list of conditions and the following disclaimer in the documentation
15 # and/or other materials provided with the distribution.
16 #
17 # * Neither the name of the copyright holder nor the names of its
18 # contributors may be used to endorse or promote products derived from
19 # this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 # -----------------------------------------------------------------------------
34 # Author A. B. G. Chalk, STFC Daresbury Lab
35 
36 ''' This module provides the OMPTaskTrans transformation.'''
37 
38 from psyclone.errors import GenerationError
39 from psyclone.domain.common.transformations import KernelModuleInlineTrans
40 from psyclone.psyGen import Kern
42  import FoldConditionalReturnExpressionsTrans
44  ParallelLoopTrans
45 from psyclone.psyir.nodes import CodeBlock, Call, IntrinsicCall
46 from psyclone.psyir.nodes import DynamicOMPTaskDirective
47 from psyclone.psyir.transformations.inline_trans import InlineTrans
49  TransformationError
50 
51 
53  ''' Apply an OpenMP Task Transformation to a Loop. The Loop must
54  be within an OpenMP Serial region (Single or Master) at codegen time.
55  Once lowering begins, no more modifications to the tree should occur
56  as the task directives do not recompute dependencies after lowering.
57  In the future it may be possible to do this through an _update_node
58  implementation.
59  '''
60 
61  def __str__(self):
62  return "Adds an 'OMP TASK' directive to a statement"
63 
64  @property
65  def name(self):
66  '''
67  :returns: the name of this transformation.
68  :rtype: str
69  '''
70  return "OMPTaskTrans"
71 
72  def validate(self, node, options=None):
73  '''
74  Validity checks for input arguments.
75 
76  :param node: the Loop node to validate.
77  :type node: :py:class:`psyclone.psyir.nodes.Loop`
78  :param options: a dictionary with options for transformations.
79  :type options: dict of string:values or None
80  '''
81  # Disallow CodeBlocks inside the region
82  if any(node.walk(CodeBlock)):
83  raise GenerationError(
84  "OMPTaskTransformation cannot be applied to a region "
85  "containing a code block")
86 
87  super().validate(node, options)
88  # Check we can apply all the required transformations on any sub
89  # nodes
90  root_ancestor = node.root
91  path_to_node = node.path_from(root_ancestor)
92  routine_copy = root_ancestor.copy()
93  node_copy = routine_copy
94  for index in path_to_node:
95  node_copy = node_copy.children[index]
96 
97  kerns = node_copy.walk(Kern)
98  kintrans = KernelModuleInlineTrans()
99  cond_trans = FoldConditionalReturnExpressionsTrans()
100  intrans = InlineTrans()
101  for kern in kerns:
102  kintrans.validate(kern)
103  cond_trans.validate(kern.get_kernel_schedule())
104  # We need to apply these transformations to ensure we can
105  # validate the InlineTrans
106  kintrans.apply(kern)
107  cond_trans.apply(kern.get_kernel_schedule())
108  kern.lower_to_language_level()
109 
110  calls = node_copy.walk(Call)
111  for call in calls:
112  # Skip over intrinsic calls as we can't inline them
113  if isinstance(call, IntrinsicCall):
114  continue
115  intrans.validate(call)
116 
117  def _directive(self, children, collapse=None):
118  '''
119  Creates the type of directive needed for this sub-class of
120  transformation.
121 
122  :param children: list of Nodes that will be the children of \
123  the created directive.
124  :type children: List[:py:class:`psyclone.psyir.nodes.Node`]
125  :param collapse: A required parameter from parent class. Must
126  never be set for TaskTrans (is None).
127  :type collapse: None.
128 
129  :raises TransformationError: if the collapse attribute is set.
130 
131  :returns: The directive created for the OpenMP Task Directive
132  :rtype: :py:class:`psyclone.psyGen.DynamicOMPTaskDirective`
133 
134  '''
135  if collapse is not None:
136  raise TransformationError("Collapse attribute should not be set "
137  "for OMPTaskTrans")
138 
139  _directive = DynamicOMPTaskDirective(children=children)
140  return _directive
141 
142  def _inline_kernels(self, node):
143  '''
144  Searches the PsyIR tree inside the directive and inlines any kern
145  objects found.
146  This is a multi-step process:
147  1. Module inline any kernels found.
148  2. Fold any conditional return expressions.
149  3. Lower kernels to language level, resulting in Call nodes.
150  4. Inline all the Call operations found.
151 
152  :param node: The node this transformation is operating on.
153  :type node: :py:class:`psyclone.psyir.nodes.Loop`
154  '''
155 
156  kerns = node.walk(Kern)
157  kintrans = KernelModuleInlineTrans()
158  cond_trans = FoldConditionalReturnExpressionsTrans()
159  intrans = InlineTrans()
160  for kern in kerns:
161  kintrans.apply(kern)
162  cond_trans.apply(kern.get_kernel_schedule())
163  kern.lower_to_language_level()
164 
165  calls = node.walk(Call)
166  for call in calls:
167  # Skip over intrinsic calls as we can't inline them
168  if isinstance(call, IntrinsicCall):
169  continue
170  intrans.apply(call)
171 
172  def apply(self, node, options=None):
173  '''Apply the OMPTaskTrans to the specified node in a Schedule.
174 
175  Can only be applied to a Loop.
176 
177  The specified node is wrapped by directives during code generation
178  like so:
179 
180  .. code-block:: fortran
181 
182  !$OMP TASK
183  ...
184  !$OMP END TASK
185 
186  At code-generation time, this node must be
187  within (i.e. a child of) an OpenMP Serial region (OpenMP Single or
188  OpenMP Master)
189 
190  Any kernels or Calls will be inlined into the region before the task
191  transformation is applied.
192 
193  :param node: the supplied node to which we will apply the \
194  OMPTaskTrans transformation
195  :type node: :py:class:`psyclone.psyir.nodes.Loop`
196  :param options: a dictionary with options for transformations\
197  and validation.
198  :type options: dictionary of string:values or None
199  '''
200  self.validatevalidatevalidatevalidatevalidate(node, options=options)
201  if not options:
202  options = {}
203  self._inline_kernels_inline_kernels(node)
204  super().apply(node, options)
def validate(self, node, options=None)
Definition: psyGen.py:2799