40 '''This module provides management of variable access information.'''
50 '''This class stores all `SingleVariableAccessInfo` instances for all
51 variables in the corresponding code section. It maintains 'location'
52 information, which is an integer number that is increased for each new
53 statement. It can be used to easily determine if one access is before
56 :param nodes: optional, a single PSyIR node or list of nodes from
57 which to initialise this object.
58 :type nodes: Optional[:py:class:`psyclone.psyir.nodes.Node` |
59 List[:py:class:`psyclone.psyir.nodes.Node`]]
60 :param options: a dictionary with options to influence which variable
61 accesses are to be collected.
62 :type options: Dict[str, Any]
63 :param Any options["COLLECT-ARRAY-SHAPE-READS"]: if this option is set
64 to a True value, arrays used as first parameter to the PSyIR query
65 operators lbound, ubound, or size will be reported as 'read'.
66 Otherwise, these accesses will be ignored.
67 :param Any options["USE-ORIGINAL-NAMES"]: if this option is set to a
68 True value, an imported symbol that is renamed (``use mod, a=>b``)
69 will be reported using the original name (``b`` in the example).
70 Otherwise these symbols will be reported using the renamed name
73 :raises InternalError: if the optional options parameter is not a
75 :raises InternalError: if the nodes parameter either is a list and
76 contains an element that is not a
77 :py:class:`psyclone.psyir.nodes.Node`, of if nodes is not a list and
78 is not of type :py:class:`psyclone.psyir.nodes.Node`
90 _DEFAULT_OPTIONS = {
"COLLECT-ARRAY-SHAPE-READS":
False,
91 "USE-ORIGINAL-NAMES":
False}
93 def __init__(self, nodes=None, options=None):
98 self.
_options_options = VariablesAccessInfo._DEFAULT_OPTIONS.copy()
100 if not isinstance(options, dict):
102 f
"VariablesAccessInfo must be a "
103 f
"dictionary or None, but got "
104 f
"'{type(options).__name__}'.")
105 self.
_options_options.update(options)
113 if isinstance(nodes, list):
115 if not isinstance(node, Node):
117 f
"One element in the node list is "
118 f
"not a Node, but of type "
121 node.reference_accesses(self)
122 elif isinstance(nodes, Node):
123 nodes.reference_accesses(self)
125 arg_type = str(type(nodes))
127 f
"Argument must be a single Node in a "
128 f
"schedule or a list of Nodes in a "
129 f
"schedule but have been passed an "
130 f
"object of type: {arg_type}")
133 '''Gives a shortened visual representation of all variables
134 and their access mode. The output is one of: READ, WRITE, READ+WRITE,
135 or READWRITE for each variable accessed.
136 READ+WRITE is used if the statement (or set of statements)
137 contain individual read and write accesses, e.g. 'a=a+1'. In this
138 case two accesses to `a` will be recorded, but the summary displayed
139 using this function will be 'READ+WRITE'. Same applies if this object
140 stores variable access information about more than one statement, e.g.
141 'a=b; b=1'. There would be two different accesses to 'b' with two
142 different locations, but the string representation would show this as
143 READ+WRITE. If a variable is is passed to a kernel for which no
144 individual variable information is available, and the metadata for
145 this kernel indicates a READWRITE access, this is marked as READWRITE
146 in the string output.'''
150 for signature
in all_signatures:
155 if self.
is_readis_read(signature):
162 output_list.append(f
"{signature}: {mode}")
163 return ", ".join(output_list)
166 '''Returns the value of the options for a specified key,
167 or None if the key is not specified in the options. If no
168 key is specified, the whole option dictionary is returned.
170 :param key: the option to query, or None if all options should
172 :type key: Optional[str]
174 :returns: the value of the option associated with the provided key
175 or the whole option dictionary if it is not supplied.
176 :rtype: Union[None, Any, dict]
178 :raises InternalError: if an invalid key is specified.
182 if key
not in VariablesAccessInfo._DEFAULT_OPTIONS:
183 valids = list(VariablesAccessInfo._DEFAULT_OPTIONS.keys())
188 f
"must be one of {valids}.")
189 return self.
_options_options.get(key,
None)
194 '''Returns the current location of this instance, which is
195 the location at which the next accesses will be stored.
196 See the Developers' Guide for more information.
198 :returns: the current location of this object.
203 '''Increases the location number.'''
206 def add_access(self, signature, access_type, node, component_indices=None):
207 '''Adds access information for the variable with the given signature.
208 If the `component_indices` parameter is not an instance of
209 `ComponentIndices`, it is used to construct an instance. Therefore it
210 can be None, a list or a list of lists of PSyIR nodes. In the case of
211 a list of lists, this will be used unmodified to construct the
212 ComponentIndices structures. If it is a simple list, it is assumed
213 that it contains the indices used in accessing the last component
214 of the signature. For example, for `a%b` with
215 `component_indices=[i,j]`, it will create `[[], [i,j]` as component
216 indices, indicating that no index is used in the first component `a`.
217 If the access is supposed to be for `a(i)%b(j)`, then the
218 `component_indices` argument must be specified as a list of lists,
221 :param signature: the signature of the variable.
222 :type signature: :py:class:`psyclone.core.Signature`
223 :param access_type: the type of access (READ, WRITE, ...)
224 :type access_type: :py:class:`psyclone.core.access_type.AccessType`
225 :param node: Node in PSyIR in which the access happens.
226 :type node: :py:class:`psyclone.psyir.nodes.Node` instance
227 :param component_indices: index information for the access.
228 :type component_indices: \
229 :py:class:`psyclone.core.component_indices.ComponentIndices`, or \
230 any other type that can be used to construct a ComponentIndices \
231 instance (None, List[:py:class:`psyclone.psyir.nodes.Node`] \
232 or List[List[:py:class:`psyclone.psyir.nodes.Node`]])
235 if not isinstance(signature, Signature):
237 f
"'{type(signature).__name__}' but expected "
238 f
"it to be of type psyclone.core.Signature.")
242 if not isinstance(component_indices, ComponentIndices):
245 if component_indices
is None:
246 component_indices = [[]] * len(signature)
247 elif isinstance(component_indices, list):
252 is_list_of_lists = all(isinstance(indx, list)
253 for indx
in component_indices)
254 if not is_list_of_lists:
255 component_indices = [[]] * (len(signature)-1) \
256 + [component_indices]
260 if len(signature) != len(component_indices):
261 raise InternalError(f
"Cannot add '{component_indices}' with "
262 f
"length {len(component_indices)} as "
263 f
"indices for '{signature}' which "
264 f
"requires {len(signature)} elements.")
266 if signature
in self:
267 self[signature].add_access_with_location(access_type,
272 var_info.add_access_with_location(access_type, self.
_location_location,
273 node, component_indices)
274 self[signature] = var_info
278 ''':returns: all signatures contained in this instance, sorted (in \
279 order to make test results reproducible).
280 :rtype: List[:py:class:`psyclone.core.signature`]
282 list_of_vars = list(self.keys())
287 '''Merges data from a VariablesAccessInfo instance to the
288 information in this instance.
290 :param other_access_info: the other VariablesAccessInfo instance.
291 :type other_access_info: \
292 :py:class:`psyclone.core.VariablesAccessInfo`
299 for signature
in other_access_info.all_signatures:
300 var_info = other_access_info[signature]
301 for access_info
in var_info.all_accesses:
304 if access_info.location > max_new_location:
305 max_new_location = access_info.location
306 new_location = access_info.location + self.
_location_location
307 if signature
in self:
308 var_info = self[signature]
311 self[signature] = var_info
313 var_info.add_access_with_location(access_info.access_type,
323 '''Checks if the specified variable signature is at least
326 :param signature: signature of the variable.
327 :type signature: :py:class:`psyclone.core.Signature`
329 :returns: True if the specified variable is written (at least \
333 :raises: KeyError if the signature name cannot be found.
336 var_access_info = self[signature]
337 return var_access_info.is_written()
340 '''Checks if the specified variable signature is at least read once.
342 :param signature: signature of the variable
343 :type signature: :py:class:`psyclone.core.Signature`
345 :returns: True if the specified variable name is read (at least \
349 :raises: KeyError if the signature cannot be found.'''
351 var_access_info = self[signature]
352 return var_access_info.is_read()
355 '''Checks if the specified variable signature has at least one
356 READWRITE access (which is typically only used in a function call).
358 :param signature: signature of the variable
359 :type signature: :py:class:`psyclone.core.Signature`
361 :returns: True if the specified variable name has (at least one) \
365 :raises: KeyError if the signature cannot be found.'''
367 var_access_info = self[signature]
368 return var_access_info.has_read_write()
374 __all__ = [
"VariablesAccessInfo"]
def is_read(self, signature)
def is_written(self, signature)
def merge(self, other_access_info)
def has_read_write(self, signature)
def add_access(self, signature, access_type, node, component_indices=None)
def options(self, key=None)