Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
18) PR #3410 towards #2668. Update more Transformations to use kwargs.

17) PR #3427. Preserve directive format casing.

16) PR #3422 for #440. Updates tests to use the Fortran backend to generate
Expand Down
24 changes: 16 additions & 8 deletions src/psyclone/psyir/transformations/omp_parallel_trans.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@
ParallelRegionTrans)
from psyclone.psyir.transformations.transformation_error import (
TransformationError)
from psyclone.utils import transformation_documentation_wrapper


@transformation_documentation_wrapper
class OMPParallelTrans(ParallelRegionTrans):
'''
Create an OpenMP PARALLEL region by inserting directives. For
Expand Down Expand Up @@ -108,28 +110,34 @@ def name(self) -> str:
'''
return "OMPParallelTrans"

def validate(self, node_list: list[Node], options=None):
def validate(self, nodes: list[Node], options=None, **kwargs):
'''
Perform OpenMP-specific validation checks.

:param node_list: list of Nodes to put within parallel region.
:type node_list: list of :py:class:`psyclone.psyir.nodes.Node`
:param nodes: list of Nodes to put within parallel region.
:param options: a dictionary with options for transformations.
:type options: Optional[Dict[str, Any]]
:param bool options["node-type-check"]: this flag controls if the \
type of the nodes enclosed in the region should be tested \
to avoid using unsupported nodes inside a region.

:raises TransformationError: if the target Nodes are already within \
some OMP parallel region.
'''
if node_list[0].ancestor(OMPDirective):
if nodes[0].ancestor(OMPDirective):
raise TransformationError("Error in OMPParallel transformation:" +
" cannot create an OpenMP PARALLEL " +
"region within another OpenMP region.")

# Now call the general validation checks
super().validate(node_list, options)
# TODO #2668: Remove options.
super().validate(nodes, options, **kwargs)

def apply(self, nodes: list[Node], options=None, **kwargs):
'''
Surrounds the provided node list with an OpenMP Parallel region.

:param nodes: list of Nodes to put within parallel region.
'''
# TODO #2668: Remove options.
super().apply(nodes, options, **kwargs)


__all__ = ["OMPParallelTrans"]
31 changes: 19 additions & 12 deletions src/psyclone/psyir/transformations/omp_taskloop_trans.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
This module provides the implementation of OMPTaskloopTrans

'''

from typing import Union
from psyclone.psyir.transformations.parallel_loop_trans import (
ParallelLoopTrans)

Expand All @@ -27,8 +27,10 @@

from psyclone.psyir.nodes import (
OMPTaskloopDirective)
from psyclone.utils import transformation_documentation_wrapper


@transformation_documentation_wrapper
class OMPTaskloopTrans(ParallelLoopTrans):
'''
Adds an OpenMP taskloop directive to a loop. Only one of grainsize or
Expand Down Expand Up @@ -230,7 +232,8 @@ def _directive(self, children, collapse=None):
nogroup=self.omp_nogroup)
return _directive

def apply(self, node, options=None, **kwargs):
def apply(self, node, options=None, nogroup: Union[bool, None] = None,
**kwargs):
'''Apply the OMPTaskloopTrans transformation to the specified node in
a Schedule. This node must be a Loop since this transformation
corresponds to wrapping the generated code with directives like so:
Expand All @@ -246,32 +249,36 @@ def apply(self, node, options=None, **kwargs):
At code-generation time (when lowering is called), this node must be
within (i.e. a child of) an OpenMP SERIAL region.

If the keyword "nogroup" is specified in the options, it will cause a
nogroup clause be generated if it is set to True. This will override
If the nogroup option is True, it will cause a
nogroup clause be generated. This will override
the value supplied to the constructor, but will only apply to the
apply call to which the value is supplied.

:param node: the supplied node to which we will apply the \
:param node: the supplied node to which we will apply the
OMPTaskloopTrans transformation
:type node: :py:class:`psyclone.psyir.nodes.Node`
:param options: a dictionary with options for transformations\
:param options: a dictionary with options for transformations
and validation.
:type options: Optional[Dict[str, Any]]
:param bool options["nogroup"]:
:param nogroup:
indicating whether a nogroup clause should be applied to
this taskloop.
this taskloop. Defaults to None, which means to use the
option defined by the transformations omp_nogroup member.

'''
if not options:
options = {}
current_nogroup = self.omp_nogroup
# If nogroup is specified it overrides that supplied to the
# constructor of the Transformation, but will be reset at the
# end of this function
self.omp_nogroup = options.get("nogroup", current_nogroup)
# TODO #2668: Remove options
if not options:
if nogroup is not None:
self.omp_nogroup = nogroup
else:
self.omp_nogroup = options.get("nogroup", current_nogroup)

try:
super().apply(node, options, **kwargs)
super().apply(node, options, nogroup=self.omp_nogroup, **kwargs)
finally:
# Reset the nogroup value to the original value
self.omp_nogroup = current_nogroup
67 changes: 37 additions & 30 deletions src/psyclone/psyir/transformations/omp_taskwait_trans.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,24 @@
applied to an OMPParallelDirective to satisfy any task-based dependencies
created by OpenMP Taskloops.'''

import warnings

from psyclone.core import VariablesAccessMap
from psyclone.errors import LazyString, InternalError
from psyclone.psyGen import Transformation
from psyclone.psyir import nodes
from psyclone.psyir.nodes import Loop, Schedule, \
OMPDoDirective, OMPTaskloopDirective, OMPSerialDirective, \
from psyclone.psyir.nodes import (
Loop, Schedule,
OMPDoDirective, OMPTaskloopDirective, OMPSerialDirective,
OMPTaskwaitDirective, OMPSingleDirective, OMPParallelDirective
from psyclone.psyir.transformations.transformation_error import \
TransformationError
)
from psyclone.psyir.transformations.transformation_error import (
TransformationError
)
from psyclone.utils import transformation_documentation_wrapper


@transformation_documentation_wrapper
class OMPTaskwaitTrans(Transformation):
'''
Adds zero or more OpenMP Taskwait directives to an OMP parallel region.
Expand Down Expand Up @@ -99,31 +106,29 @@ def __str__(self):
"region to satisfy 'OpenMP TASKLOOP' dependencies")
return rval

def validate(self, node, options=None):
def validate(self, node: OMPParallelDirective, options=None, **kwargs):
'''
Validity checks for input arguments.

:param node: the OMPParallelDirective node to validate.
:type node: :py:class:`psyclone.psyir.nodes.OMPParallelDirective`
:param options: a dictionary with options for transformations.
:type options: Optional[Dict[str, Any]]
:param bool options["fail_on_no_taskloop"]:
indicating whether this should throw an error if no \
OMPTaskloop nodes are found in this tree. This can be \
safely disabled as if there are no Taskloop nodes the \
result of this transformation is valid OpenMP code. Default \
is True.

:raises TransformationError: If the supplied node is not an \

:raises TransformationError: If the supplied node is not an
OMPParallelDirective
:raises TransformationError: If there are no OMPTaskloopDirective \
:raises TransformationError: If there are no OMPTaskloopDirective
nodes in this tree.
:raises TransformationError: If taskloop dependencies can't be \
satisfied due to dependencies across \
:raises TransformationError: If taskloop dependencies can't be
satisfied due to dependencies across
barrierless OpenMP Serial Regions.
'''
fail_on_no_taskloop = True
if options is not None:
# TODO #2668: Remove options dict.
if options is None:
self.validate_options(**kwargs)
fail_on_no_taskloop = self.get_option("fail_on_no_taskloop",
**kwargs)
else:
warnings.warn(self._deprecation_warning, DeprecationWarning, 2)
fail_on_no_taskloop = options.get("fail_on_no_taskloop", True)
# Check the supplied node is an OMPParallelDirective
if not isinstance(node, nodes.OMPParallelDirective):
Expand Down Expand Up @@ -315,7 +320,7 @@ def _eliminate_unneeded_dependencies(taskloop_positions,
:type taskloop_positions: list of int
:param dependence_positions: positions of the taskloops' dependencies.
:type dependence_positions: list of int
:param dependence_nodes: the nodes representing the forward \
:param dependence_nodes: the nodes representing the forward
dependency of each taskloop node.
:type dependence_nodes: list of :py:class:`psyclone.psyir.nodes.Node`

Expand Down Expand Up @@ -366,7 +371,8 @@ def _eliminate_unneeded_dependencies(taskloop_positions,
break
return dependence_positions, dependence_nodes

def apply(self, node, options=None):
def apply(self, node: OMPParallelDirective, options=None,
fail_on_no_taskloop: bool = True, **kwargs):
'''
Apply an OMPTaskwait Transformation to the supplied node
(which must be an OMPParallelDirective). In the generated code this
Expand All @@ -384,19 +390,19 @@ def apply(self, node, options=None):
!$OMP END PARALLEL

:param node: the node to which to apply the transformation.
:type node: :py:class:`psyclone.psyir.nodes.OMPParallelDirective`
:param options: a dictionary with options for transformations\
:param options: a dictionary with options for transformations
and validation.
:type options: Optional[Dict[str, Any]]
:param bool options["fail_on_no_taskloop"]:
indicating whether this should throw an error if no \
OMPTaskloop nodes are found in this tree. This can be \
safely disabled as if there are no Taskloop nodes the \
result of this transformation is valid OpenMP code. Default \
:param fail_on_no_taskloop:
indicating whether this should throw an error if no
OMPTaskloop nodes are found in this tree. This can be
safely disabled as if there are no Taskloop nodes the
result of this transformation is valid OpenMP code. Default
is True

'''
self.validate(node, options=options)
self.validate(node, options=options,
fail_on_no_taskloop=fail_on_no_taskloop, **kwargs)

# Find all the OpenMP Single & Master regions
task_regions = node.walk(OMPSerialDirective)
Expand Down Expand Up @@ -453,10 +459,11 @@ def apply(self, node, options=None):
dependence_position[i] = forward_dep.abs_position
dependence_node[i] = forward_dep
# Forward dependency positions are now computed for this region.
dependence_position, dependence_node = \
dependence_position, dependence_node = (
OMPTaskwaitTrans._eliminate_unneeded_dependencies(
taskloop_positions, dependence_position,
dependence_node)
)
# dependence_position now contains only the required dependencies
# to satisfy the full superset of dependencies. We can loop over
# these by index, and if dependence_position[i] is not None then
Expand Down
34 changes: 15 additions & 19 deletions src/psyclone/psyir/transformations/parallel_region_trans.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@
TransformationError)
from psyclone import psyGen
from psyclone.psyir.transformations.region_trans import RegionTrans
from psyclone.psyir.nodes import CodeBlock, Return
from psyclone.psyir.nodes import CodeBlock, Node, Return
from psyclone.utils import transformation_documentation_wrapper


@transformation_documentation_wrapper
class ParallelRegionTrans(RegionTrans, ABC):
'''
Base class for transformations that create a parallel region.
Expand All @@ -74,24 +76,20 @@ def __str__(self) -> str:

'''

def validate(self, node_list, options=None):
def validate(self, nodes: list[Node], options=None, **kwargs):
# pylint: disable=arguments-renamed
'''
Check that the supplied list of Nodes are eligible to be
put inside a parallel region.

:param list node_list: list of nodes to put into a parallel region
:param options: a dictionary with options for transformations.\
:type options: Optional[Dict[str, Any]]
:param bool options["node-type-check"]: this flag controls whether \
or not the type of the nodes enclosed in the region should be \
tested to avoid using unsupported nodes inside a region.
:param list nodes: list of nodes to put into a parallel region
:param options: a dictionary with options for transformations.

:raises TransformationError: if the supplied nodes are not all \
:raises TransformationError: if the supplied nodes are not all
children of the same parent (siblings).

'''
node_list = self.get_node_list(node_list)
node_list = self.get_node_list(nodes)

node_parent = node_list[0].parent

Expand All @@ -100,30 +98,28 @@ def validate(self, node_list, options=None):
raise TransformationError(
f"Error in {self.name} transformation: supplied nodes are "
f"not children of the same parent.")
super().validate(node_list, options)
# TODO #2668: Remove options.
super().validate(node_list, options, **kwargs)

def apply(self, target_nodes, options=None):
def apply(self, nodes: list[Node], options=None, **kwargs):
# pylint: disable=arguments-renamed
'''
Apply this transformation to a subset of the nodes within a
schedule - i.e. enclose the specified Loops in the
schedule within a single parallel region.

:param target_nodes: a single Node or a list of Nodes.
:type target_nodes: (list of) :py:class:`psyclone.psyir.nodes.Node`
:param nodes: a single Node or a list of Nodes.
:param options: a dictionary with options for transformations.
:type options: Optional[Dict[str, Any]]
:param bool options["node-type-check"]: this flag controls if the \
type of the nodes enclosed in the region should be tested \
to avoid using unsupported nodes inside a region.

'''

# Check whether we've been passed a list of nodes or just a
# single node. If the latter then we create ourselves a
# list containing just that node.
node_list = self.get_node_list(target_nodes)
self.validate(node_list, options)
node_list = self.get_node_list(nodes)
# TODO #2668: Remove options.
self.validate(node_list, options, **kwargs)

# Keep a reference to the parent of the nodes that are to be
# enclosed within a parallel region. Also keep the index of
Expand Down
Loading
Loading