39 ''' This module provides the ParallelLoopTrans transformation.'''
43 from psyclone
import psyGen
55 Adds an abstract directive (it needs to be specified by sub-classing this
56 transformation) to a loop indicating that it should be parallelised. It
57 performs some data dependency checks to guarantee that the loop can be
58 parallelised without changing the semantics of it.
66 def _directive(self, children, collapse=None):
68 Returns the directive object to insert into the Schedule.
69 Must be implemented by sub-class.
71 :param children: list of nodes that will be children of this Directive.
72 :type children: list of :py:class:`psyclone.psyir.nodes.Node`
73 :param int collapse: the number of tightly-nested loops to which \
74 this directive applies or None.
76 :returns: the new Directive node.
77 :rtype: sub-class of :py:class:`psyclone.psyir.nodes.Directive`.
82 Perform validation checks before applying the transformation
84 :param node: the node we are checking.
85 :type node: :py:class:`psyclone.psyir.nodes.Node`
86 :param options: a dictionary with options for transformations.\
87 This transform supports "collapse", which is the\
88 number of nested loops to collapse.
89 :type options: Optional[Dict[str, Any]]
90 :param int options["collapse"]: number of nested loops to collapse
92 :param bool options["force"]: whether to force parallelisation of the
93 target loop (i.e. ignore any dependence analysis).
94 :param bool options["sequential"]: whether this is a sequential loop.
96 :raises TransformationError: if the \
97 :py:class:`psyclone.psyir.nodes.Loop` loop iterates over \
99 :raises TransformationError: if 'collapse' is supplied with an \
100 invalid number of loops.
101 :raises TransformationError: if there is a data dependency that \
102 prevents the parallelisation of the loop unless \
103 `options["force"]` is True.
108 super().
validate(node, options=options)
112 collapse = options.get(
"collapse",
None)
113 ignore_dep_analysis = options.get(
"force",
False)
114 sequential = options.get(
"sequential",
False)
117 if (
not sequential
and isinstance(node, PSyLoop)
and
118 node.loop_type ==
'colours'):
120 f
"The target loop is over colours and "
121 f
"must be computed serially.")
126 if not isinstance(collapse, int):
128 f
"The 'collapse' argument must be an integer but got an "
129 f
"object of type {type(collapse)}")
132 f
"It only makes sense to collapse 2 or more loops "
133 f
"but got a value of {collapse}")
137 while isinstance(cnode, Loop):
140 cnode = cnode.loop_body[0]
141 if collapse > loop_count:
143 f
"Cannot apply COLLAPSE({collapse}) clause to a loop nest "
144 f
"containing only {loop_count} loops")
147 if sequential
or ignore_dep_analysis:
152 if not node.independent_iterations(dep_tools=dep_tools,
153 test_all_variables=
True):
156 for message
in dep_tools.get_all_messages():
157 if message.code == DTCode.WARN_SCALAR_WRITTEN_ONCE:
159 all_msg_str = [str(message)
for message
in
160 dep_tools.get_all_messages()]
161 messages =
"\n".join(all_msg_str)
163 f
"Dependency analysis failed with the following "
164 f
"messages:\n{messages}")
166 def apply(self, node, options=None):
168 Apply the Loop transformation to the specified node in a
169 Schedule. This node must be a Loop since this transformation
170 corresponds to wrapping the generated code with directives,
173 .. code-block:: fortran
181 At code-generation time (when gen_code()` is called), this node must be
182 within (i.e. a child of) a PARALLEL region.
184 :param node: the supplied node to which we will apply the \
186 :type node: :py:class:`psyclone.psyir.nodes.Node`
187 :param options: a dictionary with options for transformations. \
188 :type options: Optional[Dict[str, Any]]
189 :param int options["collapse"]: the number of loops to collapse into \
190 single iteration space or None.
197 collapse = options.get(
"collapse",
None)
201 node_parent = node.parent
202 node_position = node.position
207 directive = self.
_directive_directive([node.detach()], collapse)
210 node_parent.addchild(directive, index=node_position)