diff --git a/src/psyclone/core/access_sequence.py b/src/psyclone/core/access_sequence.py index 61e0fac6d3..2bb9c3a4ef 100644 --- a/src/psyclone/core/access_sequence.py +++ b/src/psyclone/core/access_sequence.py @@ -45,7 +45,6 @@ from psyclone.core.access_type import AccessType from psyclone.core.signature import Signature -from psyclone.errors import InternalError if TYPE_CHECKING: from psyclone.psyir.nodes import Node @@ -73,32 +72,6 @@ def __init__( def __str__(self) -> str: return f"{self._access_type}" - def change_read_to_write(self) -> None: - '''This changes the access mode from READ to WRITE. - This is used for processing assignment statements, - where the LHS is first considered to be READ, - and which is then changed to be WRITE. - - :raises InternalError: if the variable originally does not have\ - READ access. - - ''' - if self._access_type != AccessType.READ: - raise InternalError("Trying to change variable to 'WRITE' " - "which does not have 'READ' access.") - self._access_type = AccessType.WRITE - - def change_read_to_constant(self): - '''This changes the access mode from READ to CONSTANT. - - :raises InternalError: if the variable does not have READ access. - ''' - if self._access_type != AccessType.READ: - raise InternalError(f"Trying to change variable access from " - f"'READ' to 'CONSTANT' but access type is " - f" '{self._access_type}'.") - self._access_type = AccessType.CONSTANT - def component_indices(self): ''' :returns: a tuple of tuples of index expressions; one for every @@ -134,6 +107,17 @@ def access_type(self) -> AccessType: ''' return self._access_type + @access_type.setter + def access_type(self, value: AccessType) -> None: + ''' + :param value: the new access type. + ''' + if not isinstance(value, AccessType): + raise TypeError( + f"Expected AccessType but got '{type(value).__name__}'." + ) + self._access_type = value + def is_any_write(self) -> bool: ''' :returns: whether this access represents a write of any kind. @@ -319,35 +303,6 @@ def add_access(self, access_type: AccessType, node: 'Node') -> None: ''' self.append(AccessInfo(access_type, node)) - def change_read_to_constant(self): - '''This function is used to change a READ into a CONSTANT. - - :raises InternalError: if there is an access that is not READ or - INQUIRY or there is > 1 READ accesses. - ''' - read_access = None - for acc in self: - - if acc.access_type == AccessType.READ: - if read_access: - raise InternalError( - f"Trying to change variable '{self._signature}' to " - f"'CONSTANT' but it has more than one 'READ' access." - ) - read_access = acc - - elif acc.access_type not in AccessType.non_data_accesses(): - raise InternalError( - f"Variable '{self._signature}' has a '{acc.access_type}' " - f"access. change_read_to_constant() expects only " - f"inquiry accesses and a single 'READ' access.") - - if not read_access: - raise InternalError( - f"Trying to change variable '{self._signature}' to " - f"'CONSTANT' but it does not have a 'READ' access.") - read_access.change_read_to_constant() - def update(self, access_seq: AccessSequence) -> None: ''' This function adds all accesses from the given access sequence @@ -365,40 +320,6 @@ def update(self, access_seq: AccessSequence) -> None: for access_info in access_seq: self.add_access(access_info.access_type, access_info.node) - def change_read_to_write(self) -> None: - '''This function is only used when analysing an assignment statement. - The LHS has first all variables identified, which will be READ. - This function is then called to change the assigned-to variable - on the LHS to from READ to WRITE. Since the LHS is stored in a separate - AccessSequence class, it is guaranteed that there is only - one READ entry for the variable (although there maybe INQUIRY accesses - for array bounds). - - :raises InternalError: if there is an access that is not READ or - INQUIRY or there is > 1 READ access. - ''' - read_access = None - for acc in self: - - if acc.access_type == AccessType.READ: - if read_access: - raise InternalError( - f"Trying to change variable '{self._signature}' to " - f"'WRITE' but it has more than one 'READ' access.") - read_access = acc - - elif acc.access_type not in AccessType.non_data_accesses(): - raise InternalError( - f"Variable '{self._signature}' has a '{acc.access_type}' " - f"access. change_read_to_write() expects only inquiry " - f"accesses and a single 'READ' access.") - - if not read_access: - raise InternalError( - f"Trying to change variable '{self._signature}' to 'WRITE' but" - f" it does not have a 'READ' access.") - read_access.change_read_to_write() - def has_indices(self, index_variable: Optional[str] = None) -> bool: ''' Checks whether this variable accesses has any index. If the optional `index_variable` is provided, only indices involving the given diff --git a/src/psyclone/psyir/nodes/assignment.py b/src/psyclone/psyir/nodes/assignment.py index 2657366db4..a8409034d4 100644 --- a/src/psyclone/psyir/nodes/assignment.py +++ b/src/psyclone/psyir/nodes/assignment.py @@ -39,7 +39,7 @@ ''' This module contains the Assignment node implementation.''' -from psyclone.core import VariablesAccessMap +from psyclone.core import VariablesAccessMap, AccessType from psyclone.errors import InternalError from psyclone.psyir.nodes.literal import Literal from psyclone.psyir.nodes.array_reference import ArrayReference @@ -180,27 +180,15 @@ def reference_accesses(self) -> VariablesAccessMap: (a sequence of AccessTypes). ''' - # It is important that a new instance is used to handle the LHS, - # since a check in 'change_read_to_write' makes sure that there - # is only one access to the variable! lhs_accesses = self.lhs.reference_accesses() - # Now change the (one) access to the assigned variable to be WRITE. + # Now change the top (last) access to be WRITE. + if isinstance(self.lhs, Reference): + sig, _ = self.lhs.get_signature_and_indices() + lhs_accesses[sig][-1].access_type = AccessType.WRITE # Note that if the LHS is a CodeBlock then reference_accesses() will # already have given all Signatures READWRITE access. This is not # strictly correct (they should probably be UNKNOWN) and is the # subject of #2863. - if isinstance(self.lhs, Reference): - sig, _ = self.lhs.get_signature_and_indices() - var_info = lhs_accesses[sig] - try: - var_info.change_read_to_write() - except InternalError as err: - # An internal error typically indicates that the same variable - # is used twice on the LHS, e.g.: g(g(1)) = ... This is not - # supported in PSyclone. - raise NotImplementedError( - f"The variable '{self.lhs.name}' appears more than once on" - f" the left-hand side of an assignment.") from err # Merge the data (that shows now WRITE for the variable) with the # parameter to this function. It is important that first the diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index c7a384f85d..620efa9119 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -87,6 +87,137 @@ ArgDesc = namedtuple('ArgDesc', 'min_count max_count types arg_names') +def _add_argument_of_access_type( + argument: DataNode, var_acc_map: VariablesAccessMap, + access_type: AccessType +) -> None: + ''' + Adds an argument to the provided VariablesAccessMap with + the provided access_type + + :param argument: The argument to add to the VariablesAccessMap. + :param var_acc_map: The VariablesAccesMap to populate. + :param access_type: The access type to use for the input argument. + ''' + accesses = argument.reference_accesses() + if isinstance(argument, Reference): + sig, _ = argument.get_signature_and_indices() + accesses[sig][-1].access_type = access_type + var_acc_map.update(accesses) + + +def _compute_reference_accesses( + node: "IntrinsicCall", + read_indices: Iterable[int] = (), + write_indices: Iterable[int] = (), + readwrite_indices: Iterable[int] = (), + constant_indices: Iterable[int] = (), + inquiry_indices: Iterable[int] = (), + read_named_args: Iterable[str] = (), + write_named_args: Iterable[str] = (), + readwrite_named_args: Iterable[str] = (), + constant_named_args: Iterable[str] = (), + inquiry_named_args: Iterable[str] = (), +) -> VariablesAccessMap: + """General helper function for creating the reference_accesses for a + general IntrinsicCall. + This function only uses indices for non-named arguments, e.g. if + [0] is passed in as an index, but the argument at position 0 has a name + the function will skip it and will assume that the relevant _named_args + contains the name. + + :param node: the IntrinsicCall whose reference_accesses to compute. + :param read_indices: the argument indices of each read access. + :param write_indices: the argument indices of each write access. + :param constant_indices: the argument indices of each typeinfo access. + :param inquiry_indices: the argument indices of each inquiry access. + :param read_named_args: a list of named arguments that are read accesses. + :param write_named_args: a list of named arguments that are write + accesses. + :param constant_named_args: a list of named arguments that are typeinfo + accesses. + :param inquiry_named_args: a list of named arguments that are inquiry + accesses. + + :returns: the reference accesses of node. + """ + reference_accesses = VariablesAccessMap() + for ind, arg in enumerate(node.arguments): + # For indices, we only apply them if there is no argument name, + # otherwise it should be handled by the argument names. + if ind in read_indices: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READ) + continue + if ind in write_indices: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.WRITE) + continue + if ind in readwrite_indices: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READWRITE) + continue + if ind in constant_indices: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.CONSTANT) + continue + if ind in inquiry_indices: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.INQUIRY) + continue + if node.argument_names[ind] in read_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READ) + continue + if node.argument_names[ind] in write_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.WRITE) + continue + if node.argument_names[ind] in constant_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.CONSTANT) + continue + if node.argument_names[ind] in inquiry_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.INQUIRY) + continue + if node.argument_names[ind] in readwrite_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READWRITE) + continue + + return reference_accesses + + +def _reference_accesses_all_reads_with_optional_kind( + node, +) -> VariablesAccessMap: + """Helper function for the common IntrinsicCall case where all + arguments are read only, with the exception of an optional kind named + argument which is instead CONSTANT. + + :param node: The IntrinsicCall whose reference_accesses to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the reference accesses of node. + """ + kind_index = ( + node.argument_names.index("kind") + if "kind" in node.argument_names + else None + ) + reference_accesses = VariablesAccessMap() + for i, arg in enumerate(node.arguments): + accesses = arg.reference_accesses() + if kind_index == i: + if isinstance(arg, Reference): + sig, _ = arg.get_signature_and_indices() + accesses[sig][-1].access_type = AccessType.CONSTANT + reference_accesses.update(accesses) + + return reference_accesses + + def _type_of_arg_with_rank_minus_one( arg: Reference, scalar_type: ScalarType ) -> Union[ScalarType, ArrayType]: @@ -570,8 +701,6 @@ class Intrinsic(IAttr, Enum): # Fortran special-case statements (technically not Fortran intrinsics # but in PSyIR they are represented as Intrinsics) - # TODO 3060 reference_accesses NYI on Intrinsics, they are currently - # all set to None. ALLOCATE = IAttr( name="ALLOCATE", is_pure=False, @@ -589,7 +718,18 @@ class Intrinsic(IAttr, Enum): "errmsg": Reference, }, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + # All the unnamed arguments + # are write indices. + write_indices=[x for x, i in enumerate( + node.argument_names) if i is None + ], + read_named_args=["mold", "source"], + write_named_args=["stat", "errmsg"], + ) + ), ) DEALLOCATE = IAttr( name="DEALLOCATE", @@ -603,7 +743,17 @@ class Intrinsic(IAttr, Enum): arg_names=((None,),)), optional_args={"stat": Reference}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + # All the unnamed arguments + # are write indices. + write_indices=[x for x, i in enumerate( + node.argument_names) if i is None + ], + write_named_args=["stat"], + ) + ), ) NULLIFY = IAttr( name="NULLIFY", @@ -617,7 +767,13 @@ class Intrinsic(IAttr, Enum): arg_names=((None,),)), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + # All arguments are unnamed and all are written to. + write_indices=list(range(len(node.arguments))), + ) + ), ) # Fortran Intrinsics (from Fortran 2018 standard table 16.1) @@ -634,7 +790,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO 1590 Complex to real conversion unsupported. return_type=lambda node: _type_of_named_argument(node, "a"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ACHAR = IAttr( name="ACHAR", @@ -648,7 +806,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={"kind": DataNode}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ACOS = IAttr( name="ACOS", @@ -662,7 +822,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ACOSH = IAttr( name="ACOSH", @@ -676,7 +838,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ADJUSTL = IAttr( name="ADJUSTL", @@ -691,7 +855,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO 2612 This may be more complex if we support character len return_type=lambda node: _type_of_named_argument(node, "string"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ADJUSTR = IAttr( name="ADJUSTR", @@ -706,7 +872,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO 2612 This may be more complex if we support character len return_type=lambda node: _type_of_named_argument(node, "string"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) AIMAG = IAttr( name="AIMAG", @@ -721,7 +889,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO #1590 Complex numbers' precision unsupported. return_type=lambda node: UnsupportedFortranType(""), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) AINT = IAttr( name="AINT", @@ -742,7 +912,9 @@ class Intrinsic(IAttr, Enum): else node.argument_by_name("a").datatype.precision ), ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ALL = IAttr( name="ALL", @@ -761,7 +933,9 @@ class Intrinsic(IAttr, Enum): node, "mask" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ALLOCATED = IAttr( name="ALLOCATED", @@ -776,7 +950,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("",),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) ANINT = IAttr( name="ANINT", @@ -797,7 +976,9 @@ class Intrinsic(IAttr, Enum): else node.argument_by_name("a").datatype.precision ), ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ANY = IAttr( name="ANY", @@ -816,7 +997,9 @@ class Intrinsic(IAttr, Enum): node, "mask" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ASIN = IAttr( name="ASIN", @@ -830,7 +1013,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ASINH = IAttr( name="ASINH", @@ -844,7 +1029,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ASSOCIATED = IAttr( name="ASSOCIATED", @@ -858,7 +1045,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("pointer",),)), optional_args={"target": DataNode}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["pointer", "target"], + ) + ), ) ATAN = IAttr( name="ATAN", @@ -872,7 +1064,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",), ("y", "x"))), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ATAN2 = IAttr( name="ATAN2", @@ -886,7 +1080,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("y", "x"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "y"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ATANH = IAttr( name="ATANH", @@ -900,7 +1096,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ATOMIC_ADD = IAttr( name="ATOMIC_ADD", @@ -914,7 +1112,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["stat"], + ) + ), ) ATOMIC_AND = IAttr( name="ATOMIC_AND", @@ -928,7 +1133,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["stat"], + ) + ), ) ATOMIC_CAS = IAttr( name="ATOMIC_CAS", @@ -945,7 +1157,14 @@ class Intrinsic(IAttr, Enum): ), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + write_named_args=["old", "stat"], + read_named_args=["new", "compare"], + ) + ), ) ATOMIC_DEFINE = IAttr( name="ATOMIC_DEFINE", @@ -959,7 +1178,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["stat"], + ) + ), ) ATOMIC_FETCH_ADD = IAttr( name="ATOMIC_FETCH_ADD", @@ -976,7 +1202,14 @@ class Intrinsic(IAttr, Enum): ), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], + ) + ), ) ATOMIC_FETCH_AND = IAttr( name="ATOMIC_FETCH_AND", @@ -993,7 +1226,14 @@ class Intrinsic(IAttr, Enum): ), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], + ) + ), ) ATOMIC_FETCH_OR = IAttr( name="ATOMIC_FETCH_OR", @@ -1010,7 +1250,14 @@ class Intrinsic(IAttr, Enum): ), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], + ) + ), ) ATOMIC_FETCH_XOR = IAttr( name="ATOMIC_FETCH_XOR", @@ -1027,7 +1274,14 @@ class Intrinsic(IAttr, Enum): ), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], + ) + ), ) ATOMIC_OR = IAttr( name="ATOMIC_OR", @@ -1041,7 +1295,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["stat"], + ) + ), ) ATOMIC_REF = IAttr( name="ATOMIC_REF", @@ -1055,7 +1316,13 @@ class Intrinsic(IAttr, Enum): arg_names=(("value", "atom"),)), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_args=["value", "stat"], + read_named_args=["atom"], + ) + ), ) ATOMIC_XOR = IAttr( name="ATOMIC_XOR", @@ -1069,7 +1336,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["stat"], + ) + ), ) BESSEL_J0 = IAttr( name="BESSEL_J0", @@ -1087,7 +1361,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_J1 = IAttr( name="BESSEL_J1", @@ -1105,7 +1381,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_JN = IAttr( name="BESSEL_JN", @@ -1129,7 +1407,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_Y0 = IAttr( name="BESSEL_Y0", @@ -1147,7 +1427,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_Y1 = IAttr( name="BESSEL_Y1", @@ -1165,7 +1447,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_YN = IAttr( name="BESSEL_YN", @@ -1189,7 +1473,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BGE = IAttr( name="BGE", @@ -1203,7 +1489,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "j"),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BGT = IAttr( name="BGT", @@ -1217,7 +1505,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "j"),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BIT_SIZE = IAttr( name="BIT_SIZE", @@ -1231,7 +1521,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["i"], + ) + ), ) BLE = IAttr( name="BLE", @@ -1245,7 +1540,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "j"),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BLT = IAttr( name="BLT", @@ -1259,7 +1556,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "j"),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BTEST = IAttr( name="BTEST", @@ -1273,7 +1572,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "pos"),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CEILING = IAttr( name="CEILING", @@ -1291,7 +1592,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CHAR = IAttr( name="CHAR", @@ -1305,7 +1608,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={"kind": DataNode}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CMPLX = IAttr( name="CMPLX", @@ -1320,7 +1625,9 @@ class Intrinsic(IAttr, Enum): optional_args={"y": DataNode, "kind": DataNode}, # TODO #1590 Complex numbers unsupported. return_type=lambda node: UnsupportedFortranType(""), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CO_BROADCAST = IAttr( name="CO_BROADCAST", @@ -1337,7 +1644,14 @@ class Intrinsic(IAttr, Enum): ), optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["a"], + read_named_args=["source_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) CO_MAX = IAttr( name="CO_MAX", @@ -1353,7 +1667,14 @@ class Intrinsic(IAttr, Enum): "stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["a"], + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) CO_MIN = IAttr( name="CO_MIN", @@ -1369,7 +1690,14 @@ class Intrinsic(IAttr, Enum): "stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["a"], + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) CO_REDUCE = IAttr( name="CO_REDUCE", @@ -1388,7 +1716,15 @@ class Intrinsic(IAttr, Enum): "stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["a"], + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + inquiry_args=["operation"], + ) + ), ) CO_SUM = IAttr( name="CO_SUM", @@ -1404,7 +1740,14 @@ class Intrinsic(IAttr, Enum): "stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_named_args=["a"], + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) COMMAND_ARGUMENT_COUNT = IAttr( name="COMMAND_ARGUMENT_COUNT", @@ -1418,7 +1761,7 @@ class Intrinsic(IAttr, Enum): arg_names=()), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: VariablesAccessMap(), ) CONJG = IAttr( name="CONJG", @@ -1433,7 +1776,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO #1590 Complex numbers unsupported. return_type=lambda node: UnsupportedFortranType(""), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) COS = IAttr( name="COS", @@ -1447,7 +1792,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) COSH = IAttr( name="COSH", @@ -1461,7 +1808,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) COSHAPE = IAttr( name="COSHAPE", @@ -1490,7 +1839,13 @@ class Intrinsic(IAttr, Enum): ).datatype.shape ], ), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_arguments=["coarray"], + constant_named_arguments=["kind"], + ) + ), ) COUNT = IAttr( name="COUNT", @@ -1508,7 +1863,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "mask", "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CPU_TIME = IAttr( name="CPU_TIME", @@ -1522,7 +1879,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("time",),)), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_arguments=["time"], + ) + ), ) CSHIFT = IAttr( name="CSHIFT", @@ -1536,7 +1898,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("array", "shift"),)), optional_args={"dim": DataNode}, return_type=lambda node: _type_of_named_argument(node, "array"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DATE_AND_TIME = IAttr( name="DATE_AND_TIME", @@ -1555,7 +1919,12 @@ class Intrinsic(IAttr, Enum): "values": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_args=["date", "time", "zone", "values"], + ) + ), ) DBLE = IAttr( name="DBLE", @@ -1569,7 +1938,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("a",),)), optional_args={}, return_type=REAL_DOUBLE_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DIGITS = IAttr( name="DIGITS", @@ -1583,7 +1954,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) DIM = IAttr( name="DIM", @@ -1597,7 +1973,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x", "y"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DOT_PRODUCT = IAttr( name="DOT_PRODUCT", @@ -1614,7 +1992,9 @@ class Intrinsic(IAttr, Enum): return_type=lambda node: _dot_product_return_type( node ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DPROD = IAttr( name="DPROD", @@ -1628,7 +2008,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x", "y"),)), optional_args={}, return_type=REAL8_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DSHIFTL = IAttr( name="DSHIFTL", @@ -1647,7 +2029,9 @@ class Intrinsic(IAttr, Enum): "i" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DSHIFTR = IAttr( name="DSHIFTR", @@ -1666,7 +2050,9 @@ class Intrinsic(IAttr, Enum): "i" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EOSHIFT = IAttr( name="EOSHIFT", @@ -1680,7 +2066,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("array", "shift"),)), optional_args={"boundary": DataNode, "dim": DataNode}, return_type=lambda node: _type_of_named_argument(node, "array"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EPSILON = IAttr( name="EPSILON", @@ -1694,7 +2082,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) ERF = IAttr( name="ERF", @@ -1712,7 +2105,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ERFC = IAttr( name="ERFC", @@ -1730,7 +2125,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ERFC_SCALED = IAttr( name="ERFC_SCALED", @@ -1748,7 +2145,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.REAL, "x" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EVENT_QUERY = IAttr( name="EVENT_QUERY", @@ -1762,7 +2161,13 @@ class Intrinsic(IAttr, Enum): arg_names=(("event", "count"),)), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["event"], + write_named_args=["count", "stat"], + ) + ), ) EXECUTE_COMMAND_LINE = IAttr( name="EXECUTE_COMMAND_LINE", @@ -1781,7 +2186,13 @@ class Intrinsic(IAttr, Enum): "cmdmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["command", "wait"], + write_named_args=["exitstat", "cmdstat", "cmdmsg"], + ) + ), ) EXP = IAttr( name="EXP", @@ -1795,7 +2206,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EXPONENT = IAttr( name="EXPONENT", @@ -1809,7 +2222,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EXTENDS_TYPE_OF = IAttr( name="EXTENDS_TYPE_OF", @@ -1823,7 +2238,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("a", "mold"),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["a", "mold"], + ) + ), ) FAILED_IMAGES = IAttr( name="FAILED_IMAGES", @@ -1843,7 +2263,9 @@ class Intrinsic(IAttr, Enum): ), [ArrayType.Extent.DEFERRED], ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) FINDLOC = IAttr( name="FINDLOC", @@ -1863,7 +2285,9 @@ class Intrinsic(IAttr, Enum): "kind": DataNode, "back": DataNode}, return_type=_findloc_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) FLOAT = IAttr( name="FLOAT", @@ -1879,7 +2303,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("",),)), optional_args={}, return_type=REAL_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) FLOOR = IAttr( name="FLOOR", @@ -1897,7 +2323,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) FRACTION = IAttr( name="FRACTION", @@ -1911,7 +2339,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) GAMMA = IAttr( name="GAMMA", @@ -1925,7 +2355,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) GET_COMMAND = IAttr( name="GET_COMMAND", @@ -1944,7 +2376,13 @@ class Intrinsic(IAttr, Enum): "errmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_args=["command", "length", "status"], + readwrite_named_args=["errmsg"], + ) + ), ) GET_COMMAND_ARGUMENT = IAttr( name="GET_COMMAND_ARGUMENT", @@ -1963,7 +2401,14 @@ class Intrinsic(IAttr, Enum): "errmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["number"], + write_named_args=["value", "length", "status"], + readwrite_named_args=["errmsg"], + ) + ), ) GET_ENVIRONMENT_VARIABLE = IAttr( name="GET_ENVIRONMENT_VARIABLE", @@ -1983,7 +2428,14 @@ class Intrinsic(IAttr, Enum): "errmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["name", "trim_name"], + write_named_args=["value", "length", "status"], + readwrite_named_args=["errmsg"], + ) + ), ) GET_TEAM = IAttr( name="GET_TEAM", @@ -1998,7 +2450,9 @@ class Intrinsic(IAttr, Enum): optional_args={"level": DataNode}, # Unsupported return type (TEAM_TYPE from ISO_FORTRAN_ENV). return_type=lambda node: UnsupportedFortranType("TEAM_TYPE"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) HUGE = IAttr( name="HUGE", @@ -2012,7 +2466,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) HYPOT = IAttr( name="HYPOT", @@ -2026,7 +2482,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x", "y"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IACHAR = IAttr( name="IACHAR", @@ -2044,7 +2502,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IALL = IAttr( name="IALL", @@ -2069,7 +2529,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "array", "no_kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IAND = IAttr( name="IAND", @@ -2088,7 +2550,9 @@ class Intrinsic(IAttr, Enum): "i" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IANY = IAttr( name="IANY", @@ -2113,7 +2577,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "array", "no_kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IBCLR = IAttr( name="IBCLR", @@ -2127,7 +2593,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "pos"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IBITS = IAttr( name="IBITS", @@ -2141,7 +2609,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "pos", "len"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IBSET = IAttr( name="IBSET", @@ -2155,7 +2625,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "pos"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ICHAR = IAttr( name="ICHAR", @@ -2173,7 +2645,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IEOR = IAttr( name="IEOR", @@ -2192,7 +2666,9 @@ class Intrinsic(IAttr, Enum): "i" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IMAGE_INDEX = IAttr( name="IMAGE_INDEX", @@ -2208,7 +2684,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IMAGE_STATUS = IAttr( name="IMAGE_STATUS", @@ -2222,7 +2700,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("image",),)), optional_args={"team": DataNode}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) INDEX = IAttr( name="INDEX", @@ -2240,7 +2720,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) INT = IAttr( name="INT", @@ -2254,7 +2736,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=_int_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IOR = IAttr( name="IOR", @@ -2275,7 +2759,9 @@ class Intrinsic(IAttr, Enum): "i" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IPARITY = IAttr( name="IPARITY", @@ -2293,7 +2779,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={"mask": DataNode}, return_type=_iparity_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IS_CONTIGUOUS = IAttr( name="IS_CONTIGUOUS", @@ -2307,7 +2795,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("array",),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["array"], + ) + ), ) IS_IOSTAT_END = IAttr( name="IS_IOSTAT_END", @@ -2321,7 +2814,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IS_IOSTAT_EOR = IAttr( name="IS_IOSTAT_EOR", @@ -2335,7 +2830,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ISHFT = IAttr( name="ISHFT", @@ -2349,7 +2846,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ISHFTC = IAttr( name="ISHFTC", @@ -2363,7 +2862,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "shift"),)), optional_args={"size": DataNode}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) KIND = IAttr( name="KIND", @@ -2377,7 +2878,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) LBOUND = IAttr( name="LBOUND", @@ -2391,7 +2897,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("array",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["array"], + read_named_args=["dim"], + constant_named_args=["kind"], + ) + ), ) LCOBOUND = IAttr( name="LCOBOUND", @@ -2405,7 +2918,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("coarray",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["coarray"], + read_named_args=["dim"], + constant_named_args=["kind"], + ) + ), ) LEADZ = IAttr( name="LEADZ", @@ -2419,7 +2939,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LEN = IAttr( name="LEN", @@ -2437,7 +2959,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LEN_TRIM = IAttr( name="LEN_TRIM", @@ -2455,7 +2979,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LGE = IAttr( name="LGE", @@ -2470,7 +2996,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LGT = IAttr( name="LGT", @@ -2485,7 +3013,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LLE = IAttr( name="LLE", @@ -2500,7 +3030,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LLT = IAttr( name="LLT", @@ -2515,7 +3047,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOG = IAttr( name="LOG", @@ -2529,7 +3063,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOG_GAMMA = IAttr( name="LOG_GAMMA", @@ -2543,7 +3079,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOG10 = IAttr( name="LOG10", @@ -2557,7 +3095,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOGICAL = IAttr( name="LOGICAL", @@ -2577,7 +3117,9 @@ class Intrinsic(IAttr, Enum): ) if "kind" in node.argument_names else _type_of_named_argument(node, "l") ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MASKL = IAttr( name="MASKL", @@ -2595,7 +3137,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MASKR = IAttr( name="MASKR", @@ -2613,7 +3157,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MATMUL = IAttr( name="MATMUL", @@ -2628,7 +3174,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=_matmul_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MAX = IAttr( name="MAX", @@ -2644,7 +3192,9 @@ class Intrinsic(IAttr, Enum): arg_names=((None,),)), optional_args={}, return_type=lambda node: node.arguments[0].datatype, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MAXEXPONENT = IAttr( name="MAXEXPONENT", @@ -2658,7 +3208,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) MAXLOC = IAttr( name="MAXLOC", @@ -2684,7 +3239,9 @@ class Intrinsic(IAttr, Enum): node, "array" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MAXVAL = IAttr( name="MAXVAL", @@ -2702,7 +3259,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={"mask": DataNode}, return_type=_maxval_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MERGE = IAttr( name="MERGE", @@ -2718,7 +3277,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, return_type=lambda node: _type_of_named_argument(node, "tsource"), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MERGE_BITS = IAttr( name="MERGE_BITS", @@ -2732,7 +3293,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "j", "mask"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MIN = IAttr( name="MIN", @@ -2748,7 +3311,9 @@ class Intrinsic(IAttr, Enum): arg_names=((None,),)), optional_args={}, return_type=lambda node: node.arguments[0].datatype, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MINEXPONENT = IAttr( name="MINEXPONENT", @@ -2762,7 +3327,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) MINLOC = IAttr( name="MINLOC", @@ -2788,7 +3358,9 @@ class Intrinsic(IAttr, Enum): node, "array" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MINVAL = IAttr( name="MINVAL", @@ -2806,7 +3378,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={"mask": DataNode}, return_type=_maxval_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MOD = IAttr( name="MOD", @@ -2820,7 +3394,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("a", "p"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "a"), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MODULO = IAttr( name="MODULO", @@ -2834,7 +3410,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("a", "p"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "a"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MOVE_ALLOC = IAttr( name="MOVE_ALLOC", @@ -2848,7 +3426,13 @@ class Intrinsic(IAttr, Enum): arg_names=(("from", "to"),)), optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_args=["to", "stat"], + readwrite_named_args=["from", "errmsg"], + ) + ), ) MVBITS = IAttr( name="MVBITS", @@ -2865,7 +3449,13 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["from", "frompos", "len", "topos"], + write_named_args=["to"], + ) + ), ) NEAREST = IAttr( name="NEAREST", @@ -2879,7 +3469,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x", "s"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NEW_LINE = IAttr( name="NEW_LINE", @@ -2893,7 +3485,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("c"),)), optional_args={}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["c"], + ) + ), ) NINT = IAttr( name="NINT", @@ -2907,7 +3504,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NORM2 = IAttr( name="NORM2", @@ -2930,7 +3529,9 @@ class Intrinsic(IAttr, Enum): node, "x" ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NOT = IAttr( name="NOT", @@ -2947,7 +3548,9 @@ class Intrinsic(IAttr, Enum): ScalarType.Intrinsic.INTEGER, node.argument_by_name("i").datatype.precision ), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NULL = IAttr( name="NULL", @@ -2962,7 +3565,12 @@ class Intrinsic(IAttr, Enum): optional_args={"mold": DataNode}, # Returns a dissociated pointed - not supported. return_type=lambda node: UnsupportedFortranType(""), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + constant_named_args=["mold"], + ) + ), ) NUM_IMAGES = IAttr( name="NUM_IMAGES", @@ -2977,7 +3585,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) OUT_OF_RANGE = IAttr( name="OUT_OF_RANGE", @@ -2991,7 +3601,13 @@ class Intrinsic(IAttr, Enum): arg_names=(("x", "mold",),)), optional_args={"round": DataNode}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["x", "round"], + constant_named_args=["mold"], + ) + ), ) PACK = IAttr( name="PACK", @@ -3010,7 +3626,9 @@ class Intrinsic(IAttr, Enum): node.argument_by_name("array").datatype.precision), [ArrayType.Extent.DEFERRED] ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) PARITY = IAttr( name="PARITY", @@ -3028,7 +3646,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "mask"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) POPCNT = IAttr( name="POPCNT", @@ -3042,7 +3662,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) POPPAR = IAttr( name="POPPAR", @@ -3056,7 +3678,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) PRECISION = IAttr( name="PRECISION", @@ -3070,7 +3694,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) PRESENT = IAttr( name="PRESENT", @@ -3084,7 +3713,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("a",),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["a"], + ) + ), ) PRODUCT = IAttr( name="PRODUCT", @@ -3108,7 +3742,9 @@ class Intrinsic(IAttr, Enum): node.argument_by_name("array").datatype.intrinsic ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) RADIX = IAttr( name="RADIX", @@ -3122,7 +3758,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) RANDOM_INIT = IAttr( name="RANDOM_INIT", @@ -3137,7 +3778,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) RANDOM_NUMBER = IAttr( name="RANDOM_NUMBER", @@ -3151,7 +3794,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("harvest",),)), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_args=["harvest"], + ) + ), ) RANDOM_SEED = IAttr( name="RANDOM_SEED", @@ -3165,7 +3813,13 @@ class Intrinsic(IAttr, Enum): arg_names=()), optional_args={"size": DataNode, "put": DataNode, "Get": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["put"], + write_named_args=["size", "get"], + ) + ), ) RANGE = IAttr( name="RANGE", @@ -3179,7 +3833,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) RANK = IAttr( name="RANK", @@ -3193,7 +3852,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("a",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["a"], + ) + ), ) REAL = IAttr( name="REAL", @@ -3216,7 +3880,9 @@ class Intrinsic(IAttr, Enum): ), ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) REDUCE = IAttr( name="REDUCE", @@ -3236,7 +3902,9 @@ class Intrinsic(IAttr, Enum): "identity": DataNode, "ordered": DataNode}, return_type=_maxval_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) REPEAT = IAttr( name="REPEAT", @@ -3250,7 +3918,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("string", "ncopies"),)), optional_args={}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) RESHAPE = IAttr( name="RESHAPE", @@ -3266,7 +3936,9 @@ class Intrinsic(IAttr, Enum): # I went with unresolved for now as the result depends on # argument 2 (even the dimensionality). return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) RRSPACING = IAttr( name="RRSPACING", @@ -3280,7 +3952,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SAME_TYPE_AS = IAttr( name="SAME_TYPE_AS", @@ -3294,7 +3968,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("a", "b"),)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["a", "b"], + ) + ), ) SCALE = IAttr( name="SCALE", @@ -3308,7 +3987,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x", "i"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SCAN = IAttr( name="SCAN", @@ -3326,7 +4007,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SELECTED_CHAR_KIND = IAttr( name="SELECTED_CHAR_KIND", @@ -3340,7 +4023,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("name",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SELECTED_INT_KIND = IAttr( name="SELECTED_INT_KIND", @@ -3354,7 +4039,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("r",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SELECTED_REAL_KIND = IAttr( name="SELECTED_REAL_KIND", @@ -3368,7 +4055,9 @@ class Intrinsic(IAttr, Enum): arg_names=()), optional_args={"p": DataNode, "r": DataNode, "radix": DataNode}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SET_EXPONENT = IAttr( name="SET_EXPONENT", @@ -3382,7 +4071,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x", "i"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SHAPE = IAttr( name="SHAPE", @@ -3405,7 +4096,13 @@ class Intrinsic(IAttr, Enum): node.argument_by_name("source").datatype.shape)), INTEGER_TYPE)]) ), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["source"], + constant_named_args=["kind"], + ) + ), ) SHIFTA = IAttr( name="SHIFTA", @@ -3419,7 +4116,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SHIFTL = IAttr( name="SHIFTL", @@ -3433,7 +4132,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SHIFTR = IAttr( name="SHIFTR", @@ -3447,7 +4148,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SIGN = IAttr( name="SIGN", @@ -3461,7 +4164,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("a", "b"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "a"), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SIN = IAttr( name="SIN", @@ -3475,7 +4180,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SINH = IAttr( name="SINH", @@ -3489,7 +4196,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SIZE = IAttr( name="SIZE", @@ -3507,7 +4216,14 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["array"], + read_named_args=["dim"], + constant_named_args=["kind"], + ) + ), ) SPACING = IAttr( name="SPACING", @@ -3521,7 +4237,12 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) SPREAD = IAttr( name="SPREAD", @@ -3545,7 +4266,9 @@ class Intrinsic(IAttr, Enum): ArrayType) else [ArrayType.Extent.DEFERRED]) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SQRT = IAttr( name="SQRT", @@ -3560,7 +4283,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO 1590 Complex conversion unsupported. return_type=lambda node: UnsupportedFortranType(""), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) STOPPED_IMAGES = IAttr( name="STOPPED_IMAGES", @@ -3580,7 +4305,9 @@ class Intrinsic(IAttr, Enum): ) [ArrayType.Extent.DEFERRED] ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) STORAGE_SIZE = IAttr( name="STORAGE_SIZE", @@ -3598,7 +4325,13 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["a"], + constant_named_args=["kind"], + ) + ), ) SUM = IAttr( name="SUM", @@ -3622,7 +4355,9 @@ class Intrinsic(IAttr, Enum): node.argument_by_name("array").datatype.intrinsic ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SYSTEM_CLOCK = IAttr( name="SYSTEM_CLOCK", @@ -3638,7 +4373,16 @@ class Intrinsic(IAttr, Enum): "count_rate": DataNode, "count_max": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_args=[ + "count", + "count_rate", + "count_max", + ], + ) + ), ) TAN = IAttr( name="TAN", @@ -3652,7 +4396,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TANH = IAttr( name="TANH", @@ -3666,7 +4412,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TEAM_NUMBER = IAttr( name="TEAM_NUMBER", @@ -3680,7 +4428,7 @@ class Intrinsic(IAttr, Enum): arg_names=()), optional_args={"team": DataNode}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME NYI ) THIS_IMAGE = IAttr( name="THIS_IMAGE", @@ -3703,7 +4451,9 @@ class Intrinsic(IAttr, Enum): # could be added later. See # https://gcc.gnu.org/onlinedocs/gfortran/THIS_005fIMAGE.html return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TINY = IAttr( name="TINY", @@ -3718,7 +4468,12 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["x"], + ) + ), ) TRAILZ = IAttr( name="TRAILZ", @@ -3732,7 +4487,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("i",),)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TRANSFER = IAttr( name="TRANSFER", @@ -3757,7 +4514,9 @@ class Intrinsic(IAttr, Enum): ), [ArrayType.Extent.DEFERRED]) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TRANSPOSE = IAttr( name="TRANSPOSE", @@ -3776,7 +4535,9 @@ class Intrinsic(IAttr, Enum): [node.argument_by_name("matrix").datatype.shape[1], node.argument_by_name("matrix").datatype.shape[0]] ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TRIM = IAttr( name="TRIM", @@ -3790,7 +4551,9 @@ class Intrinsic(IAttr, Enum): arg_names=(("string",),)), optional_args={}, return_type=CHARACTER_TYPE, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) UBOUND = IAttr( name="UBOUND", @@ -3804,7 +4567,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("array",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["array"], + read_named_args=["dim"], + constant_named_args=["kind"], + ) + ), ) UCOBOUND = IAttr( name="UCOBOUND", @@ -3818,7 +4588,14 @@ class Intrinsic(IAttr, Enum): arg_names=(("coarray",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_named_args=["array"], + read_named_args=["dim"], + constant_named_args=["kind"], + ) + ), ) UNPACK = IAttr( name="UNPACK", @@ -3833,7 +4610,9 @@ class Intrinsic(IAttr, Enum): ), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "vector"), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) VERIFY = IAttr( name="VERIFY", @@ -3851,7 +4630,9 @@ class Intrinsic(IAttr, Enum): node, ScalarType.Intrinsic.INTEGER, "kind" ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) def __hash__(self): @@ -3968,7 +4749,6 @@ def _find_matching_interface(self) -> Tuple[str]: ] # Remove any of the interfaces that don't contain # a named non-optional argument from the list of potential - # candidate interfaces. for name in self.argument_names: if not name: continue @@ -4174,7 +4954,7 @@ def compute_argument_names(self): @classmethod def create(cls, intrinsic, arguments=()): - """Create an instance of this class given the type of intrinsic and a + '''Create an instance of this class given the type of intrinsic and a list of nodes (or name-and-node tuples) for its arguments. Any named arguments *must* come after any required arguments. @@ -4195,14 +4975,13 @@ def create(cls, intrinsic, arguments=()): :raises ValueError: if the number of supplied arguments is not valid for the specified intrinsic. - """ + ''' call = IntrinsicCall(intrinsic) if not isinstance(arguments, Iterable): raise TypeError( f"IntrinsicCall.create() 'arguments' argument should be an " - f"Iterable but found '{type(arguments).__name__}'" - ) + f"Iterable but found '{type(arguments).__name__}'") # Validate the supplied arguments. last_named_arg = None @@ -4217,8 +4996,7 @@ def create(cls, intrinsic, arguments=()): raise TypeError( f"Optional arguments to an IntrinsicCall must be " f"specified by a (str, Reference) tuple but got " - f"a {type(arg[0]).__name__} instead of a str." - ) + f"a {type(arg[0]).__name__} instead of a str.") name = arg[0].lower() last_named_arg = name if name in intrinsic.optional_args: @@ -4239,8 +5017,7 @@ def create(cls, intrinsic, arguments=()): if last_named_arg: raise ValueError( f"Found a positional argument *after* a named " - f"argument ('{last_named_arg}'). This is invalid.'" - ) + f"argument ('{last_named_arg}'). This is invalid.'") if not isinstance(arg, intrinsic.required_args.types): raise TypeError( f"The '{intrinsic.name}' intrinsic requires that " @@ -4285,25 +5062,33 @@ def reference_accesses(self) -> VariablesAccessMap: structure accessors) and the values are AccessSequence (a sequence of AccessTypes). + :raises InternalError: if the IntrinsicCall can't have argument + names computed due to ambiguity in the + intrinsic's interface being used. """ - var_accesses = VariablesAccessMap() - if self.intrinsic.is_inquiry and isinstance( - self.arguments[0], Reference - ): - # If this is an inquiry access (which doesn't actually access the - # value) then make sure we use the correct access type for the - # inquired variable, which is always the first argument. - sig, indices = self.arguments[0].get_signature_and_indices() - var_accesses.add_access(sig, AccessType.INQUIRY, self.arguments[0]) - for idx_list in indices: - for idx in idx_list: - var_accesses.update(idx.reference_accesses()) - elif self.arguments: - var_accesses.update(self.arguments[0].reference_accesses()) - - for child in self.arguments[1:]: - var_accesses.update(child.reference_accesses()) - return var_accesses + # Make sure argument names are computed if they currently haven't been + if None in self.argument_names: + try: + self.compute_argument_names() + except NotImplementedError: + # If we can't compute argument names, then we have to + # do the worst case. All arguments that are references are + # READWRITE and all other arguments are READS in this + # case as we don't know any details. + reads = [] + readwrites = [] + for i, arg in enumerate(self.arguments): + if isinstance(arg, Reference): + readwrites.append(i) + else: + reads.append(i) + return _compute_reference_accesses( + self, + read_indices=reads, + readwrite_indices=readwrites + ) + + return self.intrinsic.reference_accesses(self) # TODO #2102: Maybe the three properties below can be removed if intrinsic # is a symbol, as they would act as the super() implementation. diff --git a/src/psyclone/tests/core/access_sequence_test.py b/src/psyclone/tests/core/access_sequence_test.py index a78a5a49c9..6d21407b26 100644 --- a/src/psyclone/tests/core/access_sequence_test.py +++ b/src/psyclone/tests/core/access_sequence_test.py @@ -42,7 +42,6 @@ from psyclone.core import (AccessInfo, Signature, AccessSequence) from psyclone.core.access_type import AccessType -from psyclone.errors import InternalError from psyclone.psyir.frontend.fortran import FortranReader from psyclone.psyir.nodes import ( Assignment, Node, Reference, Return, ArrayReference) @@ -51,44 +50,30 @@ def test_access_info() -> None: - '''Test the AccessInfo class. - ''' + '''Test the AccessInfo class. ''' access_info = AccessInfo(AccessType.READ, Node()) assert access_info.access_type == AccessType.READ assert access_info.component_indices() == tuple(tuple()) assert not access_info.has_indices() assert str(access_info) == "READ" - access_info.change_read_to_write() + access_info.access_type = AccessType.WRITE assert str(access_info) == "WRITE" assert access_info.access_type == AccessType.WRITE - with pytest.raises(InternalError) as err: - access_info.change_read_to_write() - assert "Trying to change variable to 'WRITE' which does not have "\ - "'READ' access." in str(err.value) - access_info2 = AccessInfo(AccessType.READ, Node()) - assert str(access_info2) == "READ" - access_info2.change_read_to_constant() - assert str(access_info2) == "CONSTANT" - assert access_info2.access_type == AccessType.CONSTANT - with pytest.raises(InternalError) as err: - access_info2.change_read_to_constant() - assert ("Trying to change variable access from 'READ' to 'CONSTANT' " - "but access type is 'CONSTANT'." in str(err.value)) - - access_info = AccessInfo(AccessType.UNKNOWN, Node()) - assert access_info.access_type == AccessType.UNKNOWN + access_info.access_type = AccessType.CONSTANT + assert str(access_info) == "CONSTANT" + assert access_info.access_type == AccessType.CONSTANT access_info = AccessInfo(AccessType.UNKNOWN, Node()) assert access_info.access_type == AccessType.UNKNOWN - - access_info = AccessInfo(AccessType.UNKNOWN, Node()) - assert access_info.access_type == AccessType.UNKNOWN - assert access_info.is_data_access access_info = AccessInfo(AccessType.INQUIRY, Node()) assert not access_info.is_data_access + with pytest.raises(TypeError) as err: + access_info.access_type = 2 + assert "Expected AccessType but got 'int'." in str(err.value) + def test_access_info_is_any_read_or_write(): ''' Test the AccessInfo is_any_read/write methods. ''' @@ -202,7 +187,7 @@ def test_variable_access_sequence() -> None: assert not accesses.is_written() assert not accesses.is_written_first() assert not accesses.is_called() - accesses.change_read_to_write() + accesses[-1].access_type = AccessType.WRITE assert not accesses.is_read() assert accesses.is_written() assert accesses.is_written_first() @@ -210,45 +195,17 @@ def test_variable_access_sequence() -> None: assert accesses.all_read_accesses == [] assert accesses.all_write_accesses == [accesses[1]] - # Now we have one write access, which we should not be able to - # change to write again: - with pytest.raises(InternalError) as err_internal: - accesses.change_read_to_write() - assert ("Variable 'var_name' has a 'WRITE' access. change_read_to_write() " - "expects only inquiry accesses and a single 'READ' access." - in str(err_internal.value)) - with pytest.raises(IndexError) as err: _ = accesses[2] assert "list index out of range" in str(err.value) - # Add a READ access - we should not be able to - # change this read to write as there's already a WRITE access. + # Add a READ access accesses.add_access(AccessType.READ, Node()) - with pytest.raises(InternalError) as err_internal: - accesses.change_read_to_write() - assert ("Variable 'var_name' has a 'WRITE' access. change_read_to_write() " - "expects only inquiry accesses and a single 'READ' access." - in str(err_internal.value)) # And make sure the variable is not read_only if a write is added accesses.add_access(AccessType.WRITE, Node()) assert accesses.is_read_only() is False assert accesses.all_read_accesses == [accesses[2]] assert accesses.all_write_accesses == [accesses[1], accesses[3]] - # Check that we catch a case where there are no accesses at all. - accesses = AccessSequence(Signature("var_name")) - with pytest.raises(InternalError) as err_internal: - accesses.change_read_to_write() - assert "but it does not have a 'READ' access" in str(err_internal.value) - - # Test handling if there is more than one read and it is supposed - # to change read to write: - accesses.add_access(AccessType.READ, Node()) - accesses.add_access(AccessType.READ, Node()) - with pytest.raises(InternalError) as err_internal: - accesses.change_read_to_write() - assert ("Trying to change variable 'var_name' to 'WRITE' but it has more " - "than one 'READ' access." in str(err_internal.value)) # Now do just a CALL, this will have no data accesses accesses = AccessSequence(Signature("var_name")) @@ -259,43 +216,6 @@ def test_variable_access_sequence() -> None: assert not accesses.has_data_access() -def test_variable_access_sequence_read_to_constant(): - ''' - Test the read_to_constant functionality of AccessSequence - ''' - accesses = AccessSequence(Signature("var_name")) - accesses.add_access(AccessType.INQUIRY, Node()) - accesses.add_access(AccessType.READ, Node()) - accesses.change_read_to_constant() - assert not accesses.is_read() - assert not accesses.is_written() - assert not accesses.has_data_access() - - with pytest.raises(InternalError) as err: - accesses.change_read_to_constant() - assert ("Trying to change variable 'var_name' to " - "'CONSTANT' but it does not have a 'READ' access." - in str(err.value)) - - accesses.add_access(AccessType.WRITE, Node()) - with pytest.raises(InternalError) as err: - accesses.change_read_to_constant() - assert ("Variable 'var_name' has a 'WRITE' access. " - "change_read_to_constant() " - "expects only inquiry accesses and a single 'READ' access." - in str(err.value)) - - accesses = AccessSequence(Signature("var_name")) - accesses.add_access(AccessType.READ, Node()) - accesses.add_access(AccessType.READ, Node()) - - with pytest.raises(InternalError) as err: - accesses.change_read_to_constant() - assert ("Trying to change variable 'var_name' to " - "'CONSTANT' but it has more than one 'READ' access." - in str(err.value)) - - def test_variable_access_sequence_update() -> None: '''Test that the AccessSequence class updates as expected. diff --git a/src/psyclone/tests/psyir/backend/sympy_writer_test.py b/src/psyclone/tests/psyir/backend/sympy_writer_test.py index baeef17723..17b351b32f 100644 --- a/src/psyclone/tests/psyir/backend/sympy_writer_test.py +++ b/src/psyclone/tests/psyir/backend/sympy_writer_test.py @@ -352,7 +352,7 @@ def test_sympy_writer_type_map_non_canonical(fortran_reader): writer = SymPyWriter() with pytest.raises(VisitorError) as err: - _ = writer([assign.rhs]) + _ = writer.intrinsiccall_node(assign.rhs) assert ("Sympy handler can't handle an IntrinsicCall that can't have " "argument names automatically added. Use explicit argument names " "instead. Failing node was 'SUM(i, j)'." diff --git a/src/psyclone/tests/psyir/nodes/assignment_test.py b/src/psyclone/tests/psyir/nodes/assignment_test.py index d309614d03..e12650813f 100644 --- a/src/psyclone/tests/psyir/nodes/assignment_test.py +++ b/src/psyclone/tests/psyir/nodes/assignment_test.py @@ -40,7 +40,7 @@ ''' Performs py.test tests on the Assignment PSyIR node. ''' import pytest -from psyclone.core import Signature +from psyclone.core import Signature, AccessType from psyclone.errors import InternalError, GenerationError from psyclone.psyir.backend.fortran import FortranWriter from psyclone.psyir.nodes import ( @@ -366,13 +366,16 @@ def test_reference_accesses(fortran_reader): integer :: g(10) g(1) = g + 1 g(g(1)) = 1 + g(:) = 1 end program test_prog''') assigns = psyir.walk(Assignment) # Check that the lhs has been converted to a write assigns[0].reference_accesses()[Signature('g')].is_written() - # This doesn't work for nested references to the same symbol - with pytest.raises(NotImplementedError) as err: - assigns[1].reference_accesses() - assert ("The variable 'g' appears more than once on the left-hand side " - "of an assignment." in str(err.value)) + # Test nested references to the same symbol (first there is the inner + # READ to g, followed by the WRITE to the outer g) + accesses = assigns[1].reference_accesses() + assert accesses[Signature('g')][0].node == assigns[1].lhs.indices[0] + assert accesses[Signature('g')][0].access_type == AccessType.READ + assert accesses[Signature('g')][1].node == assigns[1].lhs + assert accesses[Signature('g')][1].access_type == AccessType.WRITE diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py new file mode 100644 index 0000000000..ae11a9894d --- /dev/null +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -0,0 +1,392 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022-2026, Science and Technology Facilities Council. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- +# Author: A. B. G. Chalk - STFC Darebury Lab +# ----------------------------------------------------------------------------- + +""" +This module contains pytest tests for the reference_accesses for the +IntrinsicCall class and related functions. + +TODO #2341 - tests need to be added for all of the supported intrinsics. + +""" + +from psyclone.core import AccessType, VariablesAccessMap +from psyclone.psyir.nodes import ( + ArrayReference, + Literal, + Reference, + BinaryOperation, + Call +) +from psyclone.psyir.nodes.intrinsic_call import ( + IntrinsicCall, + _reference_accesses_all_reads_with_optional_kind, + _add_argument_of_access_type, + _compute_reference_accesses, +) +from psyclone.psyir.symbols import ( + ArrayType, + DataSymbol, + INTEGER_TYPE, + RoutineSymbol +) + + +def test_add_argument_of_access_type_read(fortran_reader): + """ Test the _add_argument_of_access_type helper function with a READ.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_argument_of_access_type(ref, vam, AccessType.READ) + + sig, _ = ref.get_signature_and_indices() + assert len(vam) == 1 + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + + # Test we get expected behaviour for a Literal input. + vam = VariablesAccessMap() + lit = Literal("1", INTEGER_TYPE) + _add_argument_of_access_type(lit, vam, AccessType.READ) + assert len(vam) == 0 + + # Test we get expected behaviour for a Binop with 2 References. + symbol2 = DataSymbol("b", INTEGER_TYPE) + ref1 = Reference(symbol) + ref2 = Reference(symbol2) + binop = BinaryOperation.create( + BinaryOperation.Operator.ADD, + ref1, ref2 + ) + vam = VariablesAccessMap() + _add_argument_of_access_type(binop, vam, AccessType.READ) + assert len(vam) == 2 + sig, _ = ref1.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + sig, _ = ref2.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + + # Test we get expected behaviour for an ArrayReference with Reference + # index + symbol = DataSymbol("c", ArrayType(INTEGER_TYPE, [2])) + ref3 = Reference(symbol2) + ref = ArrayReference.create(symbol, [ref3]) + vam = VariablesAccessMap() + _add_argument_of_access_type(ref, vam, AccessType.READ) + sig, _ = ref.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + sig, _ = ref3.get_signature_and_indices() + # This is the same behaviour as an ArrayReference itself would have. + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + + code = """subroutine test + use some_mod + integer :: a, b, c + integer, dimension(100) :: d + integer, parameter :: wp = 8 + + a = MAX(a, c + b + some_func(d) + 1_wp) + end subroutine test""" + psyir = fortran_reader.psyir_from_source(code) + intrinsic = psyir.walk(IntrinsicCall)[0] + vam = VariablesAccessMap() + _add_argument_of_access_type(intrinsic.arguments[1], vam, AccessType.READ) + sigs = vam.all_signatures + assert str(sigs[0]) == "b" + assert len(vam[sigs[0]]) == 1 + assert vam[sigs[0]][0].access_type == AccessType.READ + assert str(sigs[1]) == "c" + assert len(vam[sigs[1]]) == 1 + assert vam[sigs[1]][0].access_type == AccessType.READ + assert str(sigs[2]) == "d" + assert len(vam[sigs[2]]) == 1 + assert vam[sigs[2]][0].access_type == AccessType.READWRITE + assert str(sigs[3]) == "some_func" + assert len(vam[sigs[3]]) == 1 + assert vam[sigs[3]][0].access_type == AccessType.UNKNOWN + assert str(sigs[4]) == "wp" + assert len(vam[sigs[4]]) == 1 + assert vam[sigs[4]][0].access_type == AccessType.CONSTANT + + +def test_add_argument_of_access_type_write(fortran_reader): + """ Test the _add_argument_of_access_type helper function with a WRITE.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_argument_of_access_type(ref, vam, AccessType.WRITE) + + sig, _ = ref.get_signature_and_indices() + assert len(vam) == 1 + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.WRITE + + symbol = DataSymbol("c", ArrayType(INTEGER_TYPE, [2])) + aref = ArrayReference.create(symbol, [ref]) + vam = VariablesAccessMap() + _add_argument_of_access_type(aref, vam, AccessType.WRITE) + sig, _ = aref.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.WRITE + sig, _ = ref.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + + code = """subroutine test + use some_mod + integer :: a, b, c + integer, dimension(100) :: d + integer, parameter :: wp = 8 + + CALL RANDOM_NUMBER( d(somefunc(b) + 1.0_wp)) + end subroutine test""" + psyir = fortran_reader.psyir_from_source(code) + call = psyir.walk(Call)[0] + # RANDOM_NUMBER doesn't create an IntrinsicCall in the + # PSyIR tree, so convert the resultant call into the + # IntrinsicCall we need to test. + intrinsic = IntrinsicCall.create( + IntrinsicCall.Intrinsic.RANDOM_NUMBER, + [arg.copy() for arg in call.arguments] + ) + vam = VariablesAccessMap() + _add_argument_of_access_type( + intrinsic.arguments[0], vam, AccessType.WRITE + ) + sigs = vam.all_signatures + assert str(sigs[0]) == "b" + assert len(vam[sigs[0]]) == 1 + assert vam[sigs[0]][0].access_type == AccessType.READWRITE + assert str(sigs[1]) == "d" + assert len(vam[sigs[1]]) == 1 + assert vam[sigs[1]][0].access_type == AccessType.WRITE + assert str(sigs[2]) == "somefunc" + assert len(vam[sigs[2]]) == 1 + assert vam[sigs[2]][0].access_type == AccessType.UNKNOWN + assert str(sigs[3]) == "wp" + assert len(vam[sigs[3]]) == 1 + assert vam[sigs[3]][0].access_type == AccessType.CONSTANT + + +def test_add_argument_of_access_type_readwrite(): + """ Test the _add_argument_of_access_type helper function with a + READWRITE.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_argument_of_access_type(ref, vam, AccessType.READWRITE) + + sig, _ = ref.get_signature_and_indices() + assert len(vam) == 1 + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READWRITE + + symbol = DataSymbol("c", ArrayType(INTEGER_TYPE, [2])) + aref = ArrayReference.create(symbol, [ref]) + vam = VariablesAccessMap() + _add_argument_of_access_type(aref, vam, AccessType.READWRITE) + sig, _ = aref.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READWRITE + sig, _ = ref.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + + +def test_add_argument_of_access_type_constant(): + """ Test the _add_argument_of_access_type helper function with a + CONSTANT.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_argument_of_access_type(ref, vam, AccessType.CONSTANT) + + sig, _ = ref.get_signature_and_indices() + assert len(vam) == 1 + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.CONSTANT + + # Test we skip for a Literal + vam = VariablesAccessMap() + lit = Literal("1", INTEGER_TYPE) + _add_argument_of_access_type(lit, vam, AccessType.CONSTANT) + assert len(vam) == 0 + + +def test_add_argument_of_access_type_inquiry(): + """ Test the _add_argument_of_access_type helper function with an + INQUIRY.""" + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_argument_of_access_type(ref, vam, AccessType.INQUIRY) + + sig, _ = ref.get_signature_and_indices() + assert len(vam) == 1 + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.INQUIRY + + # Test we skip for a Literal + vam = VariablesAccessMap() + lit = Literal("1", INTEGER_TYPE) + _add_argument_of_access_type(lit, vam, AccessType.INQUIRY) + assert len(vam) == 0 + + symbol = DataSymbol("c", ArrayType(INTEGER_TYPE, [2])) + aref = ArrayReference.create(symbol, [ref]) + vam = VariablesAccessMap() + _add_argument_of_access_type(aref, vam, AccessType.INQUIRY) + sig, _ = aref.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.INQUIRY + sig, _ = ref.get_signature_and_indices() + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.READ + + +def test_compute_reference_accesses(): + """ Test the _compute_reference_accesses helper function.""" + # Create some References to use to test functionality. + a_sym = DataSymbol("a", INTEGER_TYPE) + b_sym = DataSymbol("b", INTEGER_TYPE) + c_sym = DataSymbol("c", INTEGER_TYPE) + d_sym = DataSymbol("d", INTEGER_TYPE) + e_sym = DataSymbol("e", INTEGER_TYPE) + f_sym = DataSymbol("f", INTEGER_TYPE) + g_sym = DataSymbol("g", INTEGER_TYPE) + h_sym = DataSymbol("h", INTEGER_TYPE) + i_sym = DataSymbol("i", INTEGER_TYPE) + j_sym = DataSymbol("j", INTEGER_TYPE) + a_ref = Reference(a_sym) + b_ref = Reference(b_sym) + c_ref = Reference(c_sym) + d_ref = Reference(d_sym) + e_ref = Reference(e_sym) + f_ref = Reference(f_sym) + g_ref = Reference(g_sym) + h_ref = Reference(h_sym) + i_ref = Reference(i_sym) + j_ref = Reference(j_sym) + + # Create some general call to test the function. + call = Call.create( + Reference(RoutineSymbol("myname")), + [a_ref, b_ref, c_ref, d_ref, e_ref, + ("read", f_ref), ("write", g_ref), + ("readwrite", h_ref), + ("constant", i_ref), + ("inquiry", j_ref), + ] + ) + varaccesses = _compute_reference_accesses( + call, + read_indices=[0], + write_indices=[1], + readwrite_indices=[2], + constant_indices=[3], + inquiry_indices=[4], + read_named_args=["read", "not_present_1"], + write_named_args=["write", "not_present_2"], + readwrite_named_args=["readwrite", "not_present_3"], + constant_named_args=["constant", "not_present_4"], + inquiry_named_args=["inquiry", "not_present_5"], + ) + # We should only get the 10 accesses present in the Call. + assert len(varaccesses) == 10 + + sig, _ = a_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.READ + sig, _ = b_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.WRITE + sig, _ = c_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.READWRITE + sig, _ = d_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.CONSTANT + sig, _ = e_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.INQUIRY + sig, _ = f_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.READ + sig, _ = g_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.WRITE + sig, _ = h_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.READWRITE + sig, _ = i_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.CONSTANT + sig, _ = j_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.INQUIRY + + +def test_reference_accesses_all_reads_with_optional_kind(fortran_reader): + """Test the _reference_accesses_all_reads_with_optional_kind helper + function.""" + code = """subroutine test + use external_mod, only: wp + integer :: i, j + j = INT(i) + j = INT(i, kind=wp) + end subroutine test""" + psyir = fortran_reader.psyir_from_source(code) + intrinsics = psyir.walk(IntrinsicCall) + + refs = _reference_accesses_all_reads_with_optional_kind(intrinsics[0]) + sig, _ = intrinsics[0].arguments[0].get_signature_and_indices() + # All results should be reads. + for ref in refs[sig]: + assert ref.access_type == AccessType.READ + + refs = _reference_accesses_all_reads_with_optional_kind(intrinsics[1]) + # First result should be a READ, the kind should be a CONSTANT + sig, _ = intrinsics[1].arguments[0].get_signature_and_indices() + assert refs[sig][0].access_type == AccessType.READ + sig, _ = intrinsics[1].arguments[1].get_signature_and_indices() + assert refs[sig][0].access_type == AccessType.CONSTANT diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 3c8575442d..27f22646d6 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -44,14 +44,16 @@ import pytest +from psyclone.core.access_type import AccessType from psyclone.errors import InternalError from psyclone.psyir.nodes import ( ArrayReference, + Assignment, + BinaryOperation, + Call, Literal, - Reference, Schedule, - Assignment, - Call + Reference, ) from psyclone.psyir.nodes.intrinsic_call import ( IntrinsicCall, @@ -173,6 +175,32 @@ def test_intrinsiccall_datatype(fortran_reader): assert isinstance(call.datatype, UnresolvedType) +def test_intrinsiccall_reference_accesses_no_arg_names(): + """Test the case of IntrinsicCall's reference_accesses method where the + call to compute_argument_names fails.""" + # If the IntrinsicCall cannot compute the argument names (e.g. for SUM + # with no naming), it cannot guarantee the result of reference_accesses. + intrinsic = IntrinsicCall(IntrinsicCall.Intrinsic.SUM) + # References should be READWRITE. + intrinsic.addchild(Reference(DataSymbol("a", INTEGER_TYPE))) + # BinaryOperations should be READ + binop = BinaryOperation.create( + BinaryOperation.Operator.ADD, + Reference(DataSymbol("b", INTEGER_TYPE)), + Reference(DataSymbol("c", INTEGER_TYPE)) + ) + intrinsic.addchild(binop) + var_accs = intrinsic.reference_accesses() + sigs = var_accs.all_signatures + assert len(sigs) == 3 + assert str(sigs[0]) == "a" + assert var_accs[sigs[0]][0].access_type == AccessType.READWRITE + assert str(sigs[1]) == "b" + assert var_accs[sigs[1]][0].access_type == AccessType.READ + assert str(sigs[2]) == "c" + assert var_accs[sigs[2]][0].access_type == AccessType.READ + + def test_intrinsiccall_is_elemental(): """Tests the is_elemental() method works as expected. There are currently no elemental intrinsics so we can only test for diff --git a/src/psyclone/tests/psyir/nodes/omp_directives_test.py b/src/psyclone/tests/psyir/nodes/omp_directives_test.py index be60a40ba7..b01b2ee8d5 100644 --- a/src/psyclone/tests/psyir/nodes/omp_directives_test.py +++ b/src/psyclone/tests/psyir/nodes/omp_directives_test.py @@ -934,14 +934,15 @@ def test_infer_sharing_attributes(fortran_reader): assert len(sync) == 1 assert list(sync)[0].name == 'k' - # Check that kinds on literals are ignored for data sharing clauses + # Check that constants are ignored, even if in the same loop they appear + # in a location that expects a READ psyir = fortran_reader.psyir_from_source(''' subroutine my_subroutine() integer, parameter :: ikind = 4 integer :: i, scalar1, scalar2 - real, dimension(10) :: array + real, dimension(10) :: array, array2 do i = 1, 10 - array(i) = 1_ikind + INT(i, ikind) + array(i) = 1_ikind + INT(i, ikind) + array2(ikind) enddo end subroutine''') omplooptrans = OMPLoopTrans() diff --git a/src/psyclone/tests/psyir/transformations/omp_target_trans_test.py b/src/psyclone/tests/psyir/transformations/omp_target_trans_test.py index d89d1df2d4..bee98362f1 100644 --- a/src/psyclone/tests/psyir/transformations/omp_target_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/omp_target_trans_test.py @@ -445,24 +445,24 @@ def test_omptarget_nowait_multiple_dependencies(fortran_reader, def test_kind_parameters_ignored(fortran_reader): - '''Test that kind parameters used inside REAL calls don't - result in dependencies.''' - # TODO #3060: Fixing 3060 should avoid this being necessary. + '''Test that CONSTANT variables used in locations that would also + be attributed as reads don't result in dependencies.''' code = """ subroutine x() - integer, parameter :: wp = 8 + use some_mod, only: wp real, dimension(100) :: a real, dimension(100) :: b + real, dimension(100) :: c integer :: i, j do i = 1, 100 a(i) = real(i, wp) - a(i) = a(i) + 1.0_wp + a(i) = a(i) + c(wp) + 1.0_wp end do do j = 1, 100 b(j) = real(j, wp) - b(j) = b(j) + 2.0_wp + b(j) = b(j) + c(wp) + 2.0_wp end do end subroutine""" diff --git a/src/psyclone/tests/psyir/transformations/scalarisation_trans_test.py b/src/psyclone/tests/psyir/transformations/scalarisation_trans_test.py index 4a8163cb0d..06e551f327 100644 --- a/src/psyclone/tests/psyir/transformations/scalarisation_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/scalarisation_trans_test.py @@ -37,7 +37,7 @@ ''' from psyclone.core import Signature -from psyclone.psyir.nodes import Loop +from psyclone.psyir.nodes import Loop, Routine from psyclone.psyir.transformations import ScalarisationTrans from psyclone.tests.utilities import Compile @@ -698,7 +698,8 @@ def test_scalarisation_trans_apply_routinesymbol(fortran_reader, fortran_writer, tmpdir): ''' Test the application of the scalarisation transformation doesn't work when applied on an array with a RoutineSymbol as an index.''' - code = '''subroutine test + code = ''' + subroutine test integer, dimension(3) :: j integer :: i integer, allocatable, dimension(:,:,:) :: k @@ -709,7 +710,8 @@ def test_scalarisation_trans_apply_routinesymbol(fortran_reader, end subroutine test''' strans = ScalarisationTrans() psyir = fortran_reader.psyir_from_source(code) - strans.apply(psyir.children[0].children[0]) + routine = psyir.walk(Routine)[0] + strans.apply(routine.children[0]) correct = '''subroutine test() integer, dimension(3) :: j integer :: i diff --git a/src/psyclone/tests/psyir/transformations/transformations_test.py b/src/psyclone/tests/psyir/transformations/transformations_test.py index b8fc2c9135..2524810221 100644 --- a/src/psyclone/tests/psyir/transformations/transformations_test.py +++ b/src/psyclone/tests/psyir/transformations/transformations_test.py @@ -134,6 +134,7 @@ def test_accparalleltrans_validate(fortran_reader): integer, dimension(10, 10) :: A integer :: i integer :: j + character :: command do i = 1, 10 do j = 1, 10 A(i, j) = myfunc(3) @@ -146,7 +147,7 @@ def test_accparalleltrans_validate(fortran_reader): end do do i = 1, 10 do j = 1, 10 - A(i,j) = GET_COMMAND(2) + A(i, j) = ADJUSTR(command) end do end do end subroutine @@ -167,14 +168,14 @@ def test_accparalleltrans_validate(fortran_reader): with pytest.raises(TransformationError) as err: omptargettrans.validate(loops[2]) - assert ("'GET_COMMAND' is not available on the default accelerator " + assert ("'ADJUSTR' is not available on the default accelerator " "device. Use the 'device_string' option to specify a different " "device." in str(err.value)) with pytest.raises(TransformationError) as err: omptargettrans.validate(loops[2], options={'device_string': 'nvfortran-all'}) - assert ("'GET_COMMAND' is not available on the 'nvfortran-all' accelerator" + assert ("'ADJUSTR' is not available on the 'nvfortran-all' accelerator" " device. Use the 'device_string' option to specify a different " "device." in str(err.value))