Reference Guide  2.5.0
psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans Class Reference
Inheritance diagram for psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans:
Collaboration diagram for psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans:

Public Member Functions

def validate (self, node, options=None)
 
def apply (self, node, options=None)
 
- Public Member Functions inherited from psyclone.psyir.transformations.loop_trans.LoopTrans
def name (self)
 

Static Public Attributes

tuple excluded_node_types = (nodes.Return, psyGen.HaloExchange, nodes.CodeBlock)
 
- Static Public Attributes inherited from psyclone.psyir.transformations.loop_trans.LoopTrans
tuple excluded_node_types = ()
 

Detailed Description

Adds an abstract directive (it needs to be specified by sub-classing this
transformation) to a loop indicating that it should be parallelised. It
performs some data dependency checks to guarantee that the loop can be
parallelised without changing the semantics of it.

Definition at line 53 of file parallel_loop_trans.py.

Member Function Documentation

◆ apply()

def psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans.apply (   self,
  node,
  options = None 
)
Apply the Loop 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,
e.g. for OpenMP:

.. code-block:: fortran

  !$OMP DO
  do ...
     ...
  end do
  !$OMP END DO

At code-generation time (when gen_code()` is called), this node must be
within (i.e. a child of) a PARALLEL region.

:param node: the supplied node to which we will apply the \
             Loop transformation.
:type node: :py:class:`psyclone.psyir.nodes.Node`
:param options: a dictionary with options for transformations. \
:type options: Optional[Dict[str, Any]]
:param int options["collapse"]: the number of loops to collapse into \
        single iteration space or None.

Reimplemented from psyclone.psyGen.Transformation.

Reimplemented in psyclone.transformations.Dynamo0p3OMPLoopTrans, psyclone.transformations.GOceanOMPParallelLoopTrans, psyclone.transformations.OMPParallelLoopTrans, psyclone.transformations.ACCLoopTrans, psyclone.transformations.OMPTaskloopTrans, psyclone.psyir.transformations.omp_task_trans.OMPTaskTrans, and psyclone.psyir.transformations.omp_loop_trans.OMPLoopTrans.

Definition at line 166 of file parallel_loop_trans.py.

166  def apply(self, node, options=None):
167  '''
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,
171  e.g. for OpenMP:
172 
173  .. code-block:: fortran
174 
175  !$OMP DO
176  do ...
177  ...
178  end do
179  !$OMP END DO
180 
181  At code-generation time (when gen_code()` is called), this node must be
182  within (i.e. a child of) a PARALLEL region.
183 
184  :param node: the supplied node to which we will apply the \
185  Loop transformation.
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.
191 
192  '''
193  if not options:
194  options = {}
195  self.validate(node, options=options)
196 
197  collapse = options.get("collapse", None)
198 
199  # keep a reference to the node's original parent and its index as these
200  # are required and will change when we change the node's location
201  node_parent = node.parent
202  node_position = node.position
203 
204  # Add our orphan loop directive setting its parent to the node's
205  # parent and its children to the node. This calls down to the sub-class
206  # to get the type of directive we require.
207  directive = self._directive([node.detach()], collapse)
208 
209  # Add the loop directive as a child of the node's parent
210  node_parent.addchild(directive, index=node_position)

References psyclone.transformations.OMPSingleTrans._directive(), psyclone.psyir.transformations.omp_loop_trans.OMPLoopTrans._directive(), psyclone.psyir.transformations.omp_task_trans.OMPTaskTrans._directive(), psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans._directive(), psyclone.transformations.OMPTaskloopTrans._directive(), psyclone.transformations.ACCLoopTrans._directive(), psyclone.domain.lfric.kernel.lfric_kernel_metadata.LFRicKernelMetadata.validate(), psyclone.transformations.MoveTrans.validate(), psyclone.transformations.Dynamo0p3AsyncHaloExchangeTrans.validate(), psyclone.domain.common.transformations.alg_invoke_2_psy_call_trans.AlgInvoke2PSyCallTrans.validate(), psyclone.domain.common.transformations.alg_trans.AlgTrans.validate(), psyclone.domain.common.transformations.kernel_module_inline_trans.KernelModuleInlineTrans.validate(), psyclone.domain.common.transformations.raise_psyir_2_alg_trans.RaisePSyIR2AlgTrans.validate(), psyclone.domain.gocean.transformations.gocean_const_loop_bounds_trans.GOConstLoopBoundsTrans.validate(), psyclone.domain.gocean.transformations.gocean_move_iteration_boundaries_inside_kernel_trans.GOMoveIterationBoundariesInsideKernelTrans.validate(), psyclone.domain.gocean.transformations.gocean_opencl_trans.GOOpenCLTrans.validate(), psyclone.domain.gocean.transformations.raise_psyir_2_gocean_kern_trans.RaisePSyIR2GOceanKernTrans.validate(), psyclone.domain.lfric.transformations.lfric_alg_invoke_2_psy_call_trans.LFRicAlgInvoke2PSyCallTrans.validate(), psyclone.domain.lfric.transformations.raise_psyir_2_lfric_kern_trans.RaisePSyIR2LFRicKernTrans.validate(), psyclone.domain.nemo.transformations.create_nemo_invoke_schedule_trans.CreateNemoInvokeScheduleTrans.validate(), psyclone.domain.nemo.transformations.create_nemo_psy_trans.CreateNemoPSyTrans.validate(), psyclone.domain.nemo.transformations.nemo_allarrayrange2loop_trans.NemoAllArrayRange2LoopTrans.validate(), psyclone.domain.nemo.transformations.nemo_arrayrange2loop_trans.NemoArrayRange2LoopTrans.validate(), psyclone.domain.nemo.transformations.nemo_outerarrayrange2loop_trans.NemoOuterArrayRange2LoopTrans.validate(), psyclone.psyad.transformations.assignment_trans.AssignmentTrans.validate(), psyclone.psyGen.Transformation.validate(), psyclone.psyir.transformations.acc_update_trans.ACCUpdateTrans.validate(), psyclone.psyir.transformations.allarrayaccess2loop_trans.AllArrayAccess2LoopTrans.validate(), psyclone.psyir.transformations.arrayaccess2loop_trans.ArrayAccess2LoopTrans.validate(), psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans.validate(), psyclone.psyir.transformations.chunk_loop_trans.ChunkLoopTrans.validate(), psyclone.psyir.transformations.fold_conditional_return_expressions_trans.FoldConditionalReturnExpressionsTrans.validate(), psyclone.psyir.transformations.hoist_local_arrays_trans.HoistLocalArraysTrans.validate(), psyclone.psyir.transformations.hoist_loop_bound_expr_trans.HoistLoopBoundExprTrans.validate(), psyclone.psyir.transformations.hoist_trans.HoistTrans.validate(), psyclone.psyir.transformations.inline_trans.InlineTrans.validate(), psyclone.psyir.transformations.intrinsics.array_reduction_base_trans.ArrayReductionBaseTrans.validate(), psyclone.psyir.transformations.intrinsics.dotproduct2code_trans.DotProduct2CodeTrans.validate(), psyclone.psyir.transformations.intrinsics.intrinsic2code_trans.Intrinsic2CodeTrans.validate(), psyclone.psyir.transformations.intrinsics.matmul2code_trans.Matmul2CodeTrans.validate(), psyclone.psyir.transformations.loop_swap_trans.LoopSwapTrans.validate(), psyclone.psyir.transformations.loop_tiling_2d_trans.LoopTiling2DTrans.validate(), psyclone.psyir.transformations.loop_trans.LoopTrans.validate(), psyclone.psyir.transformations.omp_task_trans.OMPTaskTrans.validate(), psyclone.psyir.transformations.omp_taskwait_trans.OMPTaskwaitTrans.validate(), psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans.validate(), psyclone.psyir.transformations.reference2arrayrange_trans.Reference2ArrayRangeTrans.validate(), psyclone.psyir.transformations.replace_induction_variables_trans.ReplaceInductionVariablesTrans.validate(), psyclone.transformations.OMPDeclareTargetTrans.validate(), psyclone.transformations.DynamoOMPParallelLoopTrans.validate(), psyclone.transformations.Dynamo0p3OMPLoopTrans.validate(), psyclone.transformations.GOceanOMPLoopTrans.validate(), psyclone.transformations.Dynamo0p3RedundantComputationTrans.validate(), psyclone.transformations.Dynamo0p3KernelConstTrans.validate(), psyclone.transformations.ACCRoutineTrans.validate(), psyclone.transformations.KernelImportsToArguments.validate(), psyclone.domain.gocean.transformations.gocean_loop_fuse_trans.GOceanLoopFuseTrans.validate(), psyclone.domain.lfric.transformations.lfric_loop_fuse_trans.LFRicLoopFuseTrans.validate(), psyclone.psyir.transformations.loop_fuse_trans.LoopFuseTrans.validate(), psyclone.domain.gocean.transformations.gocean_extract_trans.GOceanExtractTrans.validate(), psyclone.domain.lfric.transformations.lfric_extract_trans.LFRicExtractTrans.validate(), psyclone.psyir.transformations.extract_trans.ExtractTrans.validate(), psyclone.psyir.transformations.nan_test_trans.NanTestTrans.validate(), psyclone.psyir.transformations.read_only_verify_trans.ReadOnlyVerifyTrans.validate(), psyclone.transformations.ParallelRegionTrans.validate(), psyclone.transformations.OMPParallelTrans.validate(), psyclone.transformations.ACCParallelTrans.validate(), psyclone.transformations.ACCKernelsTrans.validate(), psyclone.transformations.ACCDataTrans.validate(), psyclone.psyir.transformations.psy_data_trans.PSyDataTrans.validate(), psyclone.psyir.transformations.region_trans.RegionTrans.validate(), and psyclone.transformations.ACCEnterDataTrans.validate().

◆ validate()

def psyclone.psyir.transformations.parallel_loop_trans.ParallelLoopTrans.validate (   self,
  node,
  options = None 
)
Perform validation checks before applying the transformation

:param node: the node we are checking.
:type node: :py:class:`psyclone.psyir.nodes.Node`
:param options: a dictionary with options for transformations.\
                This transform supports "collapse", which is the\
                number of nested loops to collapse.
:type options: Optional[Dict[str, Any]]
:param int options["collapse"]: number of nested loops to collapse
                                or None.
:param bool options["force"]: whether to force parallelisation of the
        target loop (i.e. ignore any dependence analysis).
:param bool options["sequential"]: whether this is a sequential loop.

:raises TransformationError: if the \
        :py:class:`psyclone.psyir.nodes.Loop` loop iterates over \
        colours.
:raises TransformationError: if 'collapse' is supplied with an \
        invalid number of loops.
:raises TransformationError: if there is a data dependency that \
        prevents the parallelisation of the loop unless \
        `options["force"]` is True.

Reimplemented from psyclone.psyir.transformations.loop_trans.LoopTrans.

Reimplemented in psyclone.transformations.GOceanOMPLoopTrans, psyclone.transformations.Dynamo0p3OMPLoopTrans, psyclone.transformations.DynamoOMPParallelLoopTrans, and psyclone.psyir.transformations.omp_task_trans.OMPTaskTrans.

Definition at line 80 of file parallel_loop_trans.py.

80  def validate(self, node, options=None):
81  '''
82  Perform validation checks before applying the transformation
83 
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
91  or None.
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.
95 
96  :raises TransformationError: if the \
97  :py:class:`psyclone.psyir.nodes.Loop` loop iterates over \
98  colours.
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.
104 
105  '''
106  # Check that the supplied node is a Loop and does not contain any
107  # unsupported nodes.
108  super().validate(node, options=options)
109 
110  if not options:
111  options = {}
112  collapse = options.get("collapse", None)
113  ignore_dep_analysis = options.get("force", False)
114  sequential = options.get("sequential", False)
115 
116  # Check we are not a sequential loop
117  if (not sequential and isinstance(node, PSyLoop) and
118  node.loop_type == 'colours'):
119  raise TransformationError(f"Error in {self.name} transformation. "
120  f"The target loop is over colours and "
121  f"must be computed serially.")
122 
123  # If 'collapse' is specified, check that it is an int and that the
124  # loop nest has at least that number of loops in it
125  if collapse:
126  if not isinstance(collapse, int):
127  raise TransformationError(
128  f"The 'collapse' argument must be an integer but got an "
129  f"object of type {type(collapse)}")
130  if collapse < 2:
131  raise TransformationError(
132  f"It only makes sense to collapse 2 or more loops "
133  f"but got a value of {collapse}")
134  # Count the number of loops in the loop nest
135  loop_count = 0
136  cnode = node
137  while isinstance(cnode, Loop):
138  loop_count += 1
139  # Loops must be tightly nested (no intervening statements)
140  cnode = cnode.loop_body[0]
141  if collapse > loop_count:
142  raise TransformationError(
143  f"Cannot apply COLLAPSE({collapse}) clause to a loop nest "
144  f"containing only {loop_count} loops")
145 
146  # Check that there are no loop-carried dependencies
147  if sequential or ignore_dep_analysis:
148  return
149 
150  dep_tools = DependencyTools()
151 
152  if not node.independent_iterations(dep_tools=dep_tools,
153  test_all_variables=True):
154  # The DependencyTools also returns False for things that are
155  # not an issue, so we ignore specific messages.
156  for message in dep_tools.get_all_messages():
157  if message.code == DTCode.WARN_SCALAR_WRITTEN_ONCE:
158  continue
159  all_msg_str = [str(message) for message in
160  dep_tools.get_all_messages()]
161  messages = "\n".join(all_msg_str)
162  raise TransformationError(
163  f"Dependency analysis failed with the following "
164  f"messages:\n{messages}")
165 
Here is the caller graph for this function:

The documentation for this class was generated from the following file: