Reference Guide  2.5.0
psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans Class Reference
Inheritance diagram for psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans:
Collaboration diagram for psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans:

Public Member Functions

def apply (self, node, options=None)
 
def __str__ (self)
 
def name (self)
 
def validate (self, node, options=None)
 

Detailed Description

Provides a transformation from a PSyIR Array Range to a PSyIR
Loop. For example:

>>> from psyclone.parse.algorithm import parse
>>> from psyclone.psyGen import PSyFactory
>>> api = "nemo"
>>> filename = "tra_adv_compute.F90"
>>> ast, invoke_info = parse(filename, api=api)
>>> psy = PSyFactory(api).create(invoke_info)
>>> schedule = psy.invokes.invoke_list[0].schedule
>>>
>>> from psyclone.psyir.nodes import Assignment
>>> from psyclone.psyir.transformations import ArrayRange2LoopTrans, \
>>>     TransformationError
>>>
>>> print(schedule.view())
>>> trans = ArrayRange2LoopTrans()
>>> for assignment in schedule.walk(Assignment):
>>>     while True:
>>>         try:
>>>             trans.apply(assignment)
>>>         except TransformationError:
>>>             break
>>> print(schedule.view())

Definition at line 60 of file arrayrange2loop_trans.py.

Member Function Documentation

◆ apply()

def psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans.apply (   self,
  node,
  options = None 
)
Apply the ArrayRange2Loop transformation to the specified node. The
node must be an assignment. The rightmost range node in each array
within the assignment is replaced with a loop index and the
assignment is placed within a loop iterating over that
index. The bounds of the loop are determined from the bounds
of the array range on the left hand side of the assignment.

:param node: an Assignment node.
:type node: :py:class:`psyclone.psyir.nodes.Assignment`
:type options: Optional[Dict[str, Any]]
:param bool options["allow_string"]: whether to allow the
    transformation on a character type array range. Defaults to False.

Reimplemented from psyclone.psyGen.Transformation.

Definition at line 88 of file arrayrange2loop_trans.py.

88  def apply(self, node, options=None):
89  '''Apply the ArrayRange2Loop transformation to the specified node. The
90  node must be an assignment. The rightmost range node in each array
91  within the assignment is replaced with a loop index and the
92  assignment is placed within a loop iterating over that
93  index. The bounds of the loop are determined from the bounds
94  of the array range on the left hand side of the assignment.
95 
96  :param node: an Assignment node.
97  :type node: :py:class:`psyclone.psyir.nodes.Assignment`
98  :type options: Optional[Dict[str, Any]]
99  :param bool options["allow_string"]: whether to allow the
100  transformation on a character type array range. Defaults to False.
101 
102  '''
103  self.validate(node, options)
104 
105  parent = node.parent
106  symbol_table = node.scope.symbol_table
107  loop_variable = symbol_table.new_symbol("idx", symbol_type=DataSymbol,
108  datatype=INTEGER_TYPE)
109 
110  # Replace the rightmost range found in all arrays with the
111  # iterator and use the range from the LHS range for the loop
112  # iteration space.
113  for array in node.walk(ArrayReference):
114  for idx, child in reversed(list(enumerate(array.children))):
115  if isinstance(child, Range):
116  if array is node.lhs:
117  # Save this range to determine indexing
118  lhs_range = child
119  array.children[idx] = Reference(
120  loop_variable, parent=array)
121  break
122  position = node.position
123  # Issue #806: If Loop bounds were a Range we would just
124  # need to provide the range node which would be simpler.
125  start, stop, step = lhs_range.pop_all_children()
126  loop = Loop.create(loop_variable, start, stop, step, [node.detach()])
127  parent.children.insert(position, loop)
128 

References 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().

Here is the call graph for this function:

◆ name()

def psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans.name (   self)
:returns: the name of the transformation as a string.
:rtype: str

Reimplemented from psyclone.psyGen.Transformation.

Definition at line 134 of file arrayrange2loop_trans.py.

134  def name(self):
135  '''
136  :returns: the name of the transformation as a string.
137  :rtype: str
138 
139  '''
140  return type(self).__name__
141 
Here is the caller graph for this function:

◆ validate()

def psyclone.psyir.transformations.arrayrange2loop_trans.ArrayRange2LoopTrans.validate (   self,
  node,
  options = None 
)
Perform various checks to ensure that it is valid to apply the
ArrayRange2LoopTrans transformation to the supplied PSyIR Node.

By default the validate function will throw an TransofmrationError
on character arrays, though this can be overriden by setting the
allow_string option to True. Note that PSyclone expresses syntax such
as `character(LEN=100)` as UnsupportedFortranType, and this
transformation will convert unknown or unsupported types to loops.

:param node: the node that is being checked.
:type node: :py:class:`psyclone.psyir.nodes.Assignment`
:param options: a dictionary with options for transformations
:type options: Optional[Dict[str, Any]]
:param bool options["allow_string"]: whether to allow the
    transformation on a character type array range. Defaults to False.

:raises TransformationError: if the node argument is not an
    Assignment.
:raises TransformationError: if the node argument is an
    Assignment whose left hand side is not an ArrayReference.
:raises TransformationError: if the node argument is an
    Assignment whose left hand side is an ArrayReference that does
    not have Range specifying the access to at least one of its
    dimensions.
:raises TransformationError: if two or more of the loop ranges
    in the assignment are different or are not known to be the
    same.
:raises TransformationError: if node contains a character type
                             child and the allow_strings option is
                             not set.

Reimplemented from psyclone.psyGen.Transformation.

Definition at line 142 of file arrayrange2loop_trans.py.

142  def validate(self, node, options=None):
143  '''Perform various checks to ensure that it is valid to apply the
144  ArrayRange2LoopTrans transformation to the supplied PSyIR Node.
145 
146  By default the validate function will throw an TransofmrationError
147  on character arrays, though this can be overriden by setting the
148  allow_string option to True. Note that PSyclone expresses syntax such
149  as `character(LEN=100)` as UnsupportedFortranType, and this
150  transformation will convert unknown or unsupported types to loops.
151 
152  :param node: the node that is being checked.
153  :type node: :py:class:`psyclone.psyir.nodes.Assignment`
154  :param options: a dictionary with options for transformations
155  :type options: Optional[Dict[str, Any]]
156  :param bool options["allow_string"]: whether to allow the
157  transformation on a character type array range. Defaults to False.
158 
159  :raises TransformationError: if the node argument is not an
160  Assignment.
161  :raises TransformationError: if the node argument is an
162  Assignment whose left hand side is not an ArrayReference.
163  :raises TransformationError: if the node argument is an
164  Assignment whose left hand side is an ArrayReference that does
165  not have Range specifying the access to at least one of its
166  dimensions.
167  :raises TransformationError: if two or more of the loop ranges
168  in the assignment are different or are not known to be the
169  same.
170  :raises TransformationError: if node contains a character type
171  child and the allow_strings option is
172  not set.
173 
174  '''
175  if not isinstance(node, Assignment):
176  raise TransformationError(
177  f"Error in {self.name} transformation. The supplied node "
178  f"argument should be a PSyIR Assignment, but found "
179  f"'{type(node).__name__}'.")
180 
181  if not isinstance(node.lhs, ArrayReference):
182  raise TransformationError(
183  f"Error in {self.name} transformation. The lhs of the "
184  f"supplied Assignment node should be a PSyIR ArrayReference, "
185  f"but found '{type(node.lhs).__name__}'.")
186 
187  if not [dim for dim in node.lhs.children if isinstance(dim, Range)]:
188  raise TransformationError(
189  f"Error in {self.name} transformation. The lhs of the supplied"
190  f" Assignment node should be a PSyIR ArrayReference with at "
191  f"least one of its dimensions being a Range, but found None "
192  f"in '{node.lhs}'.")
193 
194  # TODO #2004: Note that the NEMOArrayRange2Loop transforamtion has
195  # a different implementation that accepts many more statemetns (e.g.
196  # elemental function calls) but lacks in the use of symbolics. Both
197  # implementation should be merged (as well as their tests) to one
198  # combining the advantages of both.
199 
200  # Currently we don't accept calls (with the exception of L/UBOUND)
201  for call in node.rhs.walk(Call):
202  if isinstance(call, IntrinsicCall) and call.intrinsic in \
203  (IntrinsicCall.Intrinsic.LBOUND,
204  IntrinsicCall.Intrinsic.UBOUND):
205  continue
206  raise TransformationError(
207  f"Error in {self.name} transformation. The rhs of the supplied"
208  f" Assignment contains a call '{call.debug_string()}'.")
209 
210  # Find the outermost range for the array on the lhs of the
211  # assignment and save its index.
212  for idx, child in reversed(list(enumerate(node.lhs.children))):
213  if isinstance(child, Range):
214  lhs_index = idx
215  break
216 
217  # For each array on the rhs of the assignment find the
218  # outermost range if there is one, then compare this range
219  # with the one on the lhs.
220  for array in node.walk(ArrayReference):
221  for idx, child in reversed(list(enumerate(array.children))):
222  if isinstance(child, Range):
223  # Issue #814 We should add support for adding
224  # loop variables where the ranges are
225  # different, or occur in different index
226  # locations.
227  if not node.lhs.same_range(lhs_index, array, idx):
228  # Ranges are, or may be, different so we
229  # can't safely replace this range with a
230  # loop iterator.
231  raise TransformationError(
232  f"The ArrayRange2LoopTrans transformation only "
233  f"supports ranges that are known to be the "
234  f"same as each other but array access "
235  f"'{node.lhs.name}' dimension {lhs_index} and "
236  f"'{array.name}' dimension {idx} are either "
237  f"different or can't be determined in the "
238  f"assignment '{node}'.")
239  break
240 
241  if not options:
242  options = {}
243  allow_string_array = options.get("allow_string", False)
244  # If we allow string arrays then we can skip the check.
245  if not allow_string_array:
246  # ArrayMixin datatype lookup can fail if the indices contain a
247  # Call or Intrinsic Call. We catch this exception and continue
248  # for now - TODO #1799
249  for child in node.walk((Literal, Reference)):
250  try:
251  # Skip unresolved types
252  if (isinstance(child.datatype,
253  (UnresolvedType, UnsupportedType, NoType))
254  or (isinstance(child.datatype, ArrayType) and
255  isinstance(child.datatype.datatype,
256  (UnresolvedType, UnsupportedType)))):
257  continue
258  if (child.datatype.intrinsic ==
259  ScalarType.Intrinsic.CHARACTER):
260  raise TransformationError(
261  "The ArrayRange2LoopTrans transformation doesn't "
262  "allow character arrays by default. This can be "
263  "enabled by passing the allow_string option to "
264  "the transformation."
265  )
266  except NotImplementedError:
267  pass
268 
269 
Here is the caller graph for this function:

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