Reference Guide  2.5.0
nemo_outerarrayrange2loop_trans.py
1 # -----------------------------------------------------------------------------
2 # BSD 3-Clause License
3 #
4 # Copyright (c) 2020-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 # Authors: R. W. Ford and N. Nobre, STFC Daresbury Lab
35 # Modified: A. B. G. Chalk, STFC Daresbury Lab
36 
37 '''Module providing a transformation from an Assignment node
38 containing an Array Reference node in its left-hand-side which in turn
39 has at least one PSyIR Range node specifying an access to an array
40 index (equivalent to an array assignment statement in Fortran) to the
41 equivalent loop representation using a NemoLoop node. The outermost
42 Range is chosen to be replaced as replacing any other Range node would
43 result in a reordering of the array accesses.
44 
45 '''
46 
47 from psyclone.psyir.nodes import Assignment, Reference, Range
48 from psyclone.psyir.nodes.array_mixin import ArrayMixin
50  import TransformationError
51 from psyclone.psyir.transformations import ArrayRange2LoopTrans
53  NemoArrayRange2LoopTrans
54 
55 
56 class NemoOuterArrayRange2LoopTrans(ArrayRange2LoopTrans):
57  '''Provides a transformation from the outermost PSyIR ArrayReference
58  Range to a PSyIR NemoLoop. For example:
59 
60  >>> from psyclone.parse.algorithm import parse
61  >>> from psyclone.psyGen import PSyFactory
62  >>> api = "nemo"
63  >>> filename = "tra_adv.F90" # examples/nemo/code
64  >>> ast, invoke_info = parse(filename, api=api)
65  >>> psy = PSyFactory(api).create(invoke_info)
66  >>> schedule = psy.invokes.invoke_list[0].schedule
67  >>>
68  >>> from psyclone.psyir.nodes import Assignment
69  >>> from psyclone.domain.nemo.transformations import \
70  NemoOuterArrayRange2LoopTrans
71  >>> from psyclone.transformations import TransformationError
72  >>>
73  >>> print(schedule.view())
74  >>> trans = NemoOuterArrayRange2LoopTrans()
75  >>> for assignment in schedule.walk(Assignment):
76  >>> while True:
77  >>> try:
78  >>> trans.apply(assignment)
79  >>> except TransformationError:
80  >>> break
81  >>> print(schedule.view())
82 
83  '''
84  def apply(self, node, options=None):
85  '''Apply the NemoOuterArrayRange2Loop transformation to the specified
86  node if the node is an Assignment and the left-hand-side of
87  the assignment is an Array Reference containing at least one
88  Range node specifying an access to an array index. If this is
89  the case then the outermost Range nodes within array
90  references within the assignment are replaced with references
91  to a loop index. A NemoLoop loop (with the same loop index) is
92  also placed around the modified assignment statement.
93 
94  The name of the loop index is taken from the PSyclone
95  configuration file if a name exists for the particular array
96  index, otherwise a new name is generated. The bounds of the
97  loop are taken from the Range node if they are provided. If
98  not, the loop bounds are taken from the PSyclone configuration
99  file if bounds values are supplied. If not, the LBOUND or
100  UBOUND intrinsics are used as appropriate. The type of the
101  NemoLoop is also taken from the configuration file if it is
102  supplied for that index, otherwise it is specified as being
103  "unknown".
104 
105  :param node: an Assignment node.
106  :type node: :py:class:`psyclone.psyir.nodes.Assignment`
107  :param options: a dictionary with options for \
108  transformations. No options are used in this \
109  transformation. This is an optional argument that defaults \
110  to None.
111  :type options: Optional[Dict[str, Any]]
112  :param bool options["allow_string"]: whether to allow the
113  transformation on a character type array range. Defaults to False.
114 
115  '''
116  self.validatevalidate(node, options)
117 
118  # Get deepest array in LHS (excluding inside Ranges)
119  deepest_range = node.lhs.walk(Range, stop_type=Range)[-1]
120  lhs_array_ref = deepest_range.parent
121  index = lhs_array_ref.get_outer_range_index()
122  nemo_arrayrange2loop = NemoArrayRange2LoopTrans()
123  nemo_arrayrange2loop.apply(lhs_array_ref.children[index], options)
124 
125  def __str__(self):
126  return ("Convert a PSyIR assignment to the outermost ArrayReference "
127  "Range into a PSyIR NemoLoop.")
128 
129  @property
130  def name(self):
131  '''
132  :returns: the name of the transformation.
133  :rtype: str
134 
135  '''
136  return type(self).__name__
137 
138  def validate(self, node, options=None):
139  '''Perform various checks to ensure that it is valid to apply the
140  NemoOuterArrayRange2LoopTrans transformation to the supplied
141  PSyIR Node.
142 
143  :param node: the node that is being checked.
144  :type node: :py:class:`psyclone.psyir.nodes.Assignment`
145  :param options: a dictionary with options for \
146  transformations. No options are used in this \
147  transformation. This is an optional argument that defaults \
148  to None.
149  :type options: Optional[Dict[str, Any]]
150 
151  :raises TransformationError: if the supplied node is not an \
152  Assignment node, if the Assignment node does not have an \
153  Array-type Reference node on its left hand side or if the \
154  Array-type node does not contain at least one Range \
155  node.
156 
157  '''
158  # Am I an assignment node?
159  if not isinstance(node, Assignment):
160  raise TransformationError(
161  f"Error in NemoOuterArrayRange2LoopTrans transformation. The "
162  f"supplied node argument should be a PSyIR Assignment, but "
163  f"found '{type(node).__name__}'.")
164 
165  # Is the LHS an array reference?
166  if not (isinstance(node.lhs, Reference) and node.lhs.walk(ArrayMixin)):
167  raise TransformationError(
168  f"Error in NemoOuterArrayRange2LoopTrans transformation. The "
169  f"LHS of the supplied assignment node should be a Reference "
170  f"that contains an array access somewhere in the expression, "
171  f"but found '{node.lhs}'.")
172  # Has the array reference got a range?
173  if not node.lhs.walk(Range):
174  raise TransformationError(
175  f"Error in NemoOuterArrayRange2LoopTrans transformation. The "
176  f"LHS of the supplied assignment node should be an expression "
177  f"with an array that has a Range node, but found "
178  f"'{node.lhs}'.")
179 
180 
181 # For automatic document generation
182 __all__ = [
183  'NemoOuterArrayRange2LoopTrans']