36 '''This module contains the GOMoveIterationBoundariesInsideKernelTrans.'''
42 Assignment, IfBlock, Return)
48 ''' Provides a transformation that moves iteration boundaries that are
49 encoded in the Loops lower_bound() and upper_bound() methods to a mask
50 inside the kernel with the boundaries passed as kernel arguments.
52 For example the following kernel call:
54 .. code-block:: fortran
62 will be transformed to:
64 .. code-block:: fortran
70 do i = 1, size(field, 1)
71 do j = 1, size(field, 2)
72 kernel(i, j, field, startx, stopx, starty, stopy)
76 additionally a mask like the following one will be introduced in the
79 .. code-block:: fortran
81 if (i < startx .or. i > stopx .or. j < starty .or. j > stopy) then
87 return "Move kernel iteration boundaries inside the kernel code."
91 '''Returns the name of this transformation as a string.'''
92 return "GOMoveIterationBoundariesInsideKernelTrans"
95 '''Ensure that it is valid to apply this transformation to the
98 :param node: the node to validate.
99 :type node: :py:class:`psyclone.gocean1p0.GOKern`
100 :param options: a dictionary with options for transformations.
101 :type options: Optional[Dict[str, Any]]
103 :raises TransformationError: if the node is not a GOKern.
106 if not isinstance(node, GOKern):
107 raise TransformationError(
108 f
"Error in {self.name} transformation. This transformation "
109 f
"can only be applied to 'GOKern' nodes, but found "
110 f
"'{type(node).__name__}'.")
112 def apply(self, node, options=None):
113 '''Apply this transformation to the supplied node.
115 :param node: the node to transform.
116 :type node: :py:class:`psyclone.gocean1p0.GOKern`
117 :param options: a dictionary with options for transformations.
118 :type options: Optional[Dict[str, Any]]
124 invoke_st = node.ancestor(InvokeSchedule).symbol_table
125 inner_loop = node.ancestor(Loop)
126 outer_loop = inner_loop.ancestor(Loop)
127 cursor = outer_loop.position
130 inv_xstart = invoke_st.find_or_create_tag(
131 "xstart_" + node.name, root_name=
"xstart", symbol_type=DataSymbol,
132 datatype=INTEGER_TYPE)
133 inv_xstop = invoke_st.find_or_create_tag(
134 "xstop_" + node.name, root_name=
"xstop", symbol_type=DataSymbol,
135 datatype=INTEGER_TYPE)
136 inv_ystart = invoke_st.find_or_create_tag(
137 "ystart_" + node.name, root_name=
"ystart", symbol_type=DataSymbol,
138 datatype=INTEGER_TYPE)
139 inv_ystop = invoke_st.find_or_create_tag(
140 "ystop_" + node.name, root_name=
"ystop", symbol_type=DataSymbol,
141 datatype=INTEGER_TYPE)
148 if (inner_loop.field_space ==
"go_every" and
149 outer_loop.field_space ==
"go_every" and
150 inner_loop.iteration_space ==
"go_all_pts" and
151 outer_loop.iteration_space ==
"go_all_pts"):
152 return node.root,
None
155 assign1 = Assignment.create(Reference(inv_xstart),
156 inner_loop.start_expr.copy())
157 outer_loop.parent.children.insert(cursor, assign1)
159 assign2 = Assignment.create(Reference(inv_xstop),
160 inner_loop.stop_expr.copy())
161 outer_loop.parent.children.insert(cursor, assign2)
163 assign3 = Assignment.create(Reference(inv_ystart),
164 outer_loop.start_expr.copy())
165 outer_loop.parent.children.insert(cursor, assign3)
167 assign4 = Assignment.create(Reference(inv_ystop),
168 outer_loop.stop_expr.copy())
169 outer_loop.parent.children.insert(cursor, assign4)
172 for symbol
in [inv_xstart, inv_xstop, inv_ystart, inv_ystop]:
173 node.arguments.append(symbol.name,
"go_i_scalar")
177 inner_loop.field_space =
"go_every"
178 outer_loop.field_space =
"go_every"
179 inner_loop.iteration_space =
"go_all_pts"
180 outer_loop.iteration_space =
"go_all_pts"
183 kschedule = node.get_kernel_schedule()
184 kernel_st = kschedule.symbol_table
185 iteration_indices = kernel_st.iteration_indices
186 data_arguments = kernel_st.data_arguments
190 xstart_symbol = kernel_st.new_symbol(
191 "xstart", symbol_type=DataSymbol, datatype=INTEGER_TYPE,
192 interface=ArgumentInterface(ArgumentInterface.Access.READ))
193 xstop_symbol = kernel_st.new_symbol(
194 "xstop", symbol_type=DataSymbol, datatype=INTEGER_TYPE,
195 interface=ArgumentInterface(ArgumentInterface.Access.READ))
196 ystart_symbol = kernel_st.new_symbol(
197 "ystart", symbol_type=DataSymbol, datatype=INTEGER_TYPE,
198 interface=ArgumentInterface(ArgumentInterface.Access.READ))
199 ystop_symbol = kernel_st.new_symbol(
200 "ystop", symbol_type=DataSymbol, datatype=INTEGER_TYPE,
201 interface=ArgumentInterface(ArgumentInterface.Access.READ))
202 kernel_st.specify_argument_list(
203 iteration_indices + data_arguments +
204 [xstart_symbol, xstop_symbol, ystart_symbol, ystop_symbol])
207 condition1 = BinaryOperation.create(
208 BinaryOperation.Operator.LT,
209 Reference(iteration_indices[0]),
210 Reference(xstart_symbol))
211 condition2 = BinaryOperation.create(
212 BinaryOperation.Operator.GT,
213 Reference(iteration_indices[0]),
214 Reference(xstop_symbol))
215 condition3 = BinaryOperation.create(
216 BinaryOperation.Operator.LT,
217 Reference(iteration_indices[1]),
218 Reference(ystart_symbol))
219 condition4 = BinaryOperation.create(
220 BinaryOperation.Operator.GT,
221 Reference(iteration_indices[1]),
222 Reference(ystop_symbol))
224 condition = BinaryOperation.create(
225 BinaryOperation.Operator.OR,
226 BinaryOperation.create(
227 BinaryOperation.Operator.OR,
230 BinaryOperation.create(
231 BinaryOperation.Operator.OR,
237 if_statement = IfBlock.create(condition, [Return()])
238 kschedule.children.insert(0, if_statement)
242 __all__ = [
'GOMoveIterationBoundariesInsideKernelTrans']
def validate(self, node, options=None)
def apply(self, node, options=None)