From da4ef889cbe8bbd91450e7259cb9f3d6de0862d3 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Tue, 2 Sep 2025 10:44:21 +0100 Subject: [PATCH 01/41] [skip-ci] Initial version of intrinsic call extension --- src/psyclone/psyir/nodes/intrinsic_call.py | 665 ++++++++++++------ .../tests/psyir/nodes/intrinsic_call_test.py | 81 ++- 2 files changed, 537 insertions(+), 209 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 485eab4d78..ec0ab3b0cc 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -48,12 +48,18 @@ from psyclone.psyir.nodes.literal import Literal from psyclone.psyir.nodes.reference import Reference from psyclone.psyir.symbols import IntrinsicSymbol +from psyclone.psyir.symbols.datatypes import ( + CHARACTER_TYPE, BOOLEAN_TYPE, INTEGER_TYPE, + REAL_DOUBLE_TYPE, REAL8_TYPE, REAL_TYPE, + DataType, ArrayType, ScalarType, UnresolvedType +) # pylint: disable=too-many-branches # Named tuple for describing the attributes of each intrinsic IAttr = namedtuple( 'IAttr', 'name is_pure is_elemental is_inquiry required_args optional_args' + ' return_type reference_accesses' ) # Alternatively we could use an Enum to decrive the intrinsic types # IntrinsicType = Enum('IntrinsicType', @@ -67,6 +73,66 @@ ArgDesc = namedtuple('ArgDesc', 'min_count max_count types') +def _get_first_argument_type(node) -> DataType: + '''Helper function for the common IntrinsicCall case where + the return type matches exactly the datatype of the first argument. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the datatype of the first argument of the IntrinsicCall. + ''' + return node.arguments[0].datatype + +# Anyone using this? +def _get_first_argument_type_with_optional_kind(node) -> DataType: + '''Helper function for the common IntrinsicCall case where the + return type is the Intrinsic of the first argument, with an optional + kind parameter which may override the precision. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the datatype of the first argument of the IntrinsicCall. + ''' + if "kind" not in node.argument_names: + return node.arguments[0].datatype + else: + kind = node.arguments[node.argument_names.index("kind")] + return_type = node.arguments[0].datatype.copy() + return_type._precision = kind + return return_type + +def _get_first_argument_logical_kind_with_optional_dim(node) -> DataType: + '''Helper function for the common IntrinsicCall case where the + return type is a Scalar logical with the kind of the first argument, + unless an option dim parameter is given in which case an array with + rank is given instead. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + ''' + dtype = ScalarType(ScalarType.Intrinsic.BOOLEAN, + node.arguments[0].datatype.precision) + if "dim" not in node.argument_names: + return dtype + else: + # If dim is given then this should return an array, but we + # don't necessarily know the dimensions of the resulting array + # at compile time. It will have one fewer dimension than the + # input. + arg = node.arguments[0] + shape = arg.datatype.shape + if len(shape) == 1: + return dtype + else: + # For now we don't attempt to work out the shape. + new_shape = [ArrayType.Extent.DEFERRED]*(len(shape)-1) + return ArrayType(dtype, new_shape) + + class IntrinsicCall(Call): ''' Node representing a call to an intrinsic routine (function or subroutine). This can be found as a standalone statement @@ -94,7 +160,8 @@ class Intrinsic(IAttr, Enum): IAttr namedtuple format: NAME = IAttr(name, is_pure, is_elemental, is_inquiry, - required_args, optional_args) + required_args, optional_args, return_type, + reference_accesses) Note that name is duplicated inside IAttr because each item in the Enum must have a different value, and without the name that would @@ -103,642 +170,826 @@ class Intrinsic(IAttr, Enum): ''' # Fortran special-case statements (technically not Fortran intrinsics # but in PSyIR they are represented as Intrinsics) + # TODO 3060 reference_accesses ALLOCATE = IAttr( 'ALLOCATE', False, False, False, ArgDesc(1, None, Reference), {"mold": Reference, "source": Reference, "stat": Reference, - "errmsg": Reference}) + "errmsg": Reference}, None, None) DEALLOCATE = IAttr( 'DEALLOCATE', False, False, False, - ArgDesc(1, None, Reference), {"stat": Reference}) + ArgDesc(1, None, Reference), {"stat": Reference}, + None, None) NULLIFY = IAttr( 'NULLIFY', False, False, False, - ArgDesc(1, None, Reference), {}) + ArgDesc(1, None, Reference), {}, None, None) # Fortran Intrinsics (from Fortran 2018 standard table 16.1) ABS = IAttr( 'ABS', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # TODO 1590 Complex conversion unsupported. + _get_first_argument_type, + None) ACHAR = IAttr( 'ACHAR', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, + CHARACTER_TYPE, None) ACOS = IAttr( 'ACOS', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + _get_first_argument_type, None) ACOSH = IAttr( 'ACOSH', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + _get_first_argument_type, None) ADJUSTL = IAttr( 'ADJUSTL', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # TODO 2612 This may be more complex if we support character len + _get_first_argument_type, + None) ADJUSTR = IAttr( 'ADJUSTR', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # TODO 2612 This may be more complex if we support character len + _get_first_argument_type, + None) AIMAG = IAttr( 'AIMAG', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # TODO #1590 Complex numbers' precision unsupported. + lambda node: UnresolvedType(), + None) AINT = IAttr( 'AINT', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, + lambda node: ( + ScalarType( + ScalarType.Intrinsic.REAL, + (node.arguments[node.argument_names.index("kind")] + if "kind" in node.argument_names else + node.arguments[0].datatype.precision)) + ), None) ALL = IAttr( 'ALL', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode}) # ? + ArgDesc(1, 1, DataNode), {"dim": DataNode}, + _get_first_argument_logical_kind_with_optional_dim, + None) ALLOCATED = IAttr( 'ALLOCATED', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + BOOLEAN_TYPE, None) ANINT = IAttr( 'ANINT', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, + lambda node: ( + ScalarType( + ScalarType.Intrinsic.REAL, + (node.arguments[node.argument_names.index("kind")] + if "kind" not in node.argument_names else + arguments[0].datatype.precision)) + ), None) ANY = IAttr( 'ANY', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode}) # ? + ArgDesc(1, 1, DataNode), {"dim": DataNode}, + # FIXME Return type + None, None) ASIN = IAttr( 'ASIN', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) ASINH = IAttr( 'ASINH', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) ASSOCIATED = IAttr( 'ASSOCIATED', False, False, True, - ArgDesc(1, 1, DataNode), {"target": DataNode}) + ArgDesc(1, 1, DataNode), {"target": DataNode}, + BOOLEAN_TYPE, None) ATAN = IAttr( 'ATAN', True, True, False, - ArgDesc(1, 2, DataNode), {}) + ArgDesc(1, 2, DataNode), {}, + # FIXME Return type + None, None) ATAN2 = IAttr( 'ATAN2', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + # FIXME Return type + None, None) ATANH = IAttr( 'ATANH', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) ATOMIC_ADD = IAttr( 'ATOMIC_ADD', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) ATOMIC_AND = IAttr( 'ATOMIC_AND', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) ATOMIC_CAS = IAttr( 'ATOMIC_CAS', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) ATOMIC_DEFINE = IAttr( 'ATOMIC_DEFINE', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) ATOMIC_FETCH_ADD = IAttr( 'ATOMIC_FETCH_ADD', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}) + ArgDesc(3, 3, DataNode), {"stat": DataNode}, + None, None) ATOMIC_FETCH_AND = IAttr( 'ATOMIC_FETCH_AND', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}) + ArgDesc(3, 3, DataNode), {"stat": DataNode}, + None, None) ATOMIC_FETCH_OR = IAttr( 'ATOMIC_FETCH_OR', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}) + ArgDesc(3, 3, DataNode), {"stat": DataNode}, + None, None) ATOMIC_FETCH_XOR = IAttr( 'ATOMIC_FETCH_XOR', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}) + ArgDesc(3, 3, DataNode), {"stat": DataNode}, + None, None) ATOMIC_OR = IAttr( 'ATOMIC_OR', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) ATOMIC_REF = IAttr( 'ATOMIC_REF', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) ATOMIC_XOR = IAttr( 'ATOMIC_XOR', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) BESSEL_J0 = IAttr( 'BESSEL_J0', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) BESSEL_J1 = IAttr( 'BESSEL_J1', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) BESSEL_JN = IAttr( 'BESSEL_JN', True, None, False, - ArgDesc(2, 3, DataNode), {}) + ArgDesc(2, 3, DataNode), {}, + # FIXME Return type + None, None) BESSEL_Y0 = IAttr( 'BESSEL_Y0', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) BESSEL_Y1 = IAttr( 'BESSEL_Y1', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) BESSEL_YN = IAttr( 'BESSEL_YN', True, None, False, - ArgDesc(2, 3, DataNode), {}) + ArgDesc(2, 3, DataNode), {}, + # FIXME Return type + None, None) BGE = IAttr( 'BGE', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + BOOLEAN_TYPE, None) BGT = IAttr( 'BGT', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + BOOLEAN_TYPE, None) BIT_SIZE = IAttr( 'BIT_SIZE', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + INTEGER_TYPE, None) BLE = IAttr( 'BLE', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + BOOLEAN_TYPE, None) BLT = IAttr( 'BLT', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + BOOLEAN_TYPE, None) BTEST = IAttr( 'BTEST', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + BOOLEAN_TYPE, None) CEILING = IAttr( 'CEILING', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, + # FIXME Return type + None, None) CHAR = IAttr( 'CHAR', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, + # FIXME Return type + None, None) CMPLX = IAttr( 'CMPLX', True, True, False, - ArgDesc(1, 1, DataNode), {"Y": DataNode, "kind": DataNode}) + ArgDesc(1, 1, DataNode), {"Y": DataNode, "kind": DataNode}, + # FIXME Return type + None, None) CO_BROADCAST = IAttr( 'CO_BROADCAST', True, False, False, - ArgDesc(1, 2, DataNode), {"stat": DataNode, "errmsg": DataNode}) + ArgDesc(1, 2, DataNode), {"stat": DataNode, "errmsg": DataNode}, + None, None) CO_MAX = IAttr( 'CO_MAX', True, False, False, ArgDesc(1, 1, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}) + {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, + None, None) CO_MIN = IAttr( 'CO_MIN', True, False, False, ArgDesc(1, 1, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}) + {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, + None, None) CO_REDUCE = IAttr( 'CO_REDUCE', True, False, False, ArgDesc(1, 2, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}) + {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, + None, None) CO_SUM = IAttr( 'CO_SUM', True, False, False, ArgDesc(1, 1, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}) + {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, + None, None) COMMAND_ARGUMENT_COUNT = IAttr( 'COMMAND_ARGUMENT_COUNT', True, False, False, - ArgDesc(0, 0, None), {}) + ArgDesc(0, 0, None), {}, + INTEGER_TYPE, None) CONJG = IAttr( 'CONJG', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) COS = IAttr( 'COS', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) COSH = IAttr( 'COSH', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) COSHAPE = IAttr( 'COSHAPE', True, False, True, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, + # FIXME Return type + None, None) COUNT = IAttr( 'COUNT', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, + # FIXME Return type + None, None) CPU_TIME = IAttr( 'CPU_TIME', False, False, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + None, None) CSHIFT = IAttr( 'CSHIFT', True, False, False, - ArgDesc(2, 2, DataNode), {"dim": DataNode}) + ArgDesc(2, 2, DataNode), {"dim": DataNode}, + # FIXME Return type + None, None) DATE_AND_TIME = IAttr( 'DATE_AND_TIME', False, False, False, ArgDesc(0, 0, DataNode), {"date": DataNode, "time": DataNode, - "zone": DataNode, "values": DataNode}) + "zone": DataNode, "values": DataNode}, + None, None) DBLE = IAttr( 'DBLE', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + REAL_DOUBLE_TYPE, None) DIGITS = IAttr( 'DIGITS', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + INTEGER_TYPE, None) DIM = IAttr( 'DIM', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + # FIXME Return type + None, None) DOT_PRODUCT = IAttr( 'DOT_PRODUCT', True, False, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + # FIXME Return type + None, None) DPROD = IAttr( 'DPROD', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + REAL8_TYPE, None) DSHIFTL = IAttr( 'DSHIFTL', True, True, False, - ArgDesc(3, 3, DataNode), {}) + ArgDesc(3, 3, DataNode), {}, + # FIXME Return type + None, None) DSHIFTR = IAttr( 'DSHIFTR', True, True, False, - ArgDesc(3, 3, DataNode), {}) + ArgDesc(3, 3, DataNode), {}, + # FIXME Return type + None, None) EOSHIFT = IAttr( 'EOSHIFT', True, False, False, - ArgDesc(2, 2, DataNode), {"boundary": DataNode, "dim": DataNode}) + ArgDesc(2, 2, DataNode), {"boundary": DataNode, "dim": DataNode}, + # FIXME Return type + None, None) EPSILON = IAttr( 'EPSILON', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) ERF = IAttr( 'ERF', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) ERFC = IAttr( 'ERFC', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) ERFC_SCALED = IAttr( 'ERFC_SCALED', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) EVENT_QUERY = IAttr( 'EVENT_QUERY', False, False, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode}, + None, None) EXECUTE_COMMAND_LINE = IAttr( 'EXECUTE_COMMAND_LINE', False, False, False, ArgDesc(2, 2, DataNode), {"wait": DataNode, "exitstat": DataNode, - "cmdstat": DataNode, "cmdmsg": DataNode}) + "cmdstat": DataNode, "cmdmsg": DataNode}, + None, None) EXP = IAttr( 'EXP', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) EXPONENT = IAttr( 'EXPONENT', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + INTEGER_TYPE, None) EXTENDS_TYPE_OF = IAttr( 'EXTENDS_TYPE_OF', True, False, True, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, + BOOLEAN_TYPE, None) FAILED_IMAGES = IAttr( 'FAILED_IMAGES', False, False, False, - ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}) + ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}, + # FIXME Return type + None, None) FINDLOC = IAttr( 'FINDLOC', True, False, False, ArgDesc(2, 3, DataNode), - {"mask": DataNode, "kind": DataNode, "back": DataNode}) + {"mask": DataNode, "kind": DataNode, "back": DataNode}, + # FIXME Return type + None, None) FLOAT = IAttr( 'FLOAT', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + REAL_TYPE, None) FLOOR = IAttr( 'FLOOR', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, + # FIXME Return type + None, None) FRACTION = IAttr( 'FRACTION', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) GAMMA = IAttr( 'GAMMA', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, + # FIXME Return type + None, None) GET_COMMAND = IAttr( 'GET_COMMAND', False, False, False, ArgDesc(0, 0, DataNode), {"command": DataNode, "length": DataNode, - "status": DataNode, "errmsg": DataNode}) + "status": DataNode, "errmsg": DataNode}, + None, None) GET_COMMAND_ARGUMENT = IAttr( 'GET_COMMAND_ARGUMENT', False, False, False, ArgDesc(1, 1, DataNode), {"value": DataNode, "length": DataNode, - "status": DataNode, "errmsg": DataNode}) + "status": DataNode, "errmsg": DataNode}, + None, None) GET_ENVIRONMENT_VARIABLE = IAttr( 'GET_ENVIRONMENT_VARIABLE', False, False, False, ArgDesc(1, 1, DataNode), {"value": DataNode, "length": DataNode, "status": DataNode, - "trim_name": DataNode, "errmsg": DataNode}) + "trim_name": DataNode, "errmsg": DataNode}, + None, None) GET_TEAM = IAttr( 'GET_TEAM', True, False, False, - ArgDesc(0, 0, DataNode), {"level": DataNode}) + ArgDesc(0, 0, DataNode), {"level": DataNode}, + # FIXME Return type + None, None) HUGE = IAttr( 'HUGE', True, False, True, - ArgDesc(1, 1, (Reference, Literal)), {}) + ArgDesc(1, 1, (Reference, Literal)), {}, + # FIXME Return type + None, None) HYPOT = IAttr( 'HYPOT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, + # FIXME Return type + None, None) IACHAR = IAttr( 'IACHAR', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, + # FIXME Return type + None, None) IALL = IAttr( 'IALL', True, False, False, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, + # FIXME Return type + None, None) IAND = IAttr( 'IAND', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, + # FIXME Return type + None, None) IANY = IAttr( 'IANY', True, False, False, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, + # FIXME Return type + None, None) IBCLR = IAttr( 'IBCLR', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, + # FIXME Return type + None, None) IBITS = IAttr( 'IBITS', True, True, False, - ArgDesc(3, 3, (DataNode)), {}) + ArgDesc(3, 3, (DataNode)), {}, + # FIXME Return type + None, None) IBSET = IAttr( 'IBSET', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, + # FIXME Return type + None, None) ICHAR = IAttr( 'ICHAR', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, + # FIXME Return type + None, None) IEOR = IAttr( 'IEOR', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, + # FIXME Return type + None, None) IMAGE_INDEX = IAttr( 'IMAGE_INDEX', True, False, True, - ArgDesc(2, 3, (DataNode)), {}) + ArgDesc(2, 3, (DataNode)), {}, + INTEGER_TYPE, None) IMAGE_STATUS = IAttr( 'IMAGE_STATUS', True, False, False, - ArgDesc(1, 1, (DataNode)), {"team": DataNode}) + ArgDesc(1, 1, (DataNode)), {"team": DataNode}, + INTEGER_TYPE, None) INDEX = IAttr( 'INDEX', True, True, False, - ArgDesc(2, 2, (DataNode)), {"back": DataNode, "kind": DataNode}) + ArgDesc(2, 2, (DataNode)), {"back": DataNode, "kind": DataNode}, + # FIXME Return type + None, None) INT = IAttr( 'INT', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, + # FIXME Return type + None, None) IOR = IAttr( 'IOR', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, + # FIXME Return type + None, None) IPARITY = IAttr( 'IPARITY', True, False, False, - ArgDesc(1, 2, (DataNode)), {"mask": DataNode}) - ISHFT = IAttr( - 'ISHFT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) - ISHFTC = IAttr( - 'ISHFTC', True, True, False, - ArgDesc(2, 2, (DataNode)), {"size": DataNode}) + ArgDesc(1, 2, (DataNode)), {"mask": DataNode}, + # FIXME Return type + None, None) IS_CONTIGUOUS = IAttr( 'IS_CONTIGUOUS', True, False, True, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) IS_IOSTAT_END = IAttr( 'IS_IOSTAT_END', True, True, False, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) IS_IOSTAT_EOR = IAttr( 'IS_IOSTAT_EOR', True, True, False, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) + ISHFT = IAttr( + 'ISHFT', True, True, False, + ArgDesc(2, 2, (DataNode)), {}, + # FIXME Return type + None, None) + ISHFTC = IAttr( + 'ISHFTC', True, True, False, + ArgDesc(2, 2, (DataNode)), {"size": DataNode}, + # FIXME Return type + None, None) KIND = IAttr( 'KIND', True, False, True, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) LBOUND = IAttr( 'LBOUND', True, False, True, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, + None, None) LCOBOUND = IAttr( 'LCOBOUND', True, False, True, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, + None, None) LEADZ = IAttr( 'LEADZ', True, True, False, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) LEN = IAttr( 'LEN', True, False, True, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) LEN_TRIM = IAttr( 'LEN_TRIM', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) LGE = IAttr( 'LGE', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, None, None) LGT = IAttr( 'LGT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, None, None) LLE = IAttr( 'LLE', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, None, None) LLT = IAttr( 'LLT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}) + ArgDesc(2, 2, (DataNode)), {}, None, None) LOG = IAttr( 'LOG', True, True, False, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) LOG_GAMMA = IAttr( 'LOG_GAMMA', True, True, False, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) LOG10 = IAttr( 'LOG10', True, True, False, - ArgDesc(1, 1, (DataNode)), {}) + ArgDesc(1, 1, (DataNode)), {}, None, None) LOGICAL = IAttr( 'LOGICAL', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) MASKL = IAttr( 'MASKL', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) MASKR = IAttr( 'MASKR', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}) + ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) MATMUL = IAttr( 'MATMUL', True, False, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, None, None) MAX = IAttr( 'MAX', True, True, False, - ArgDesc(2, None, DataNode), {}) + ArgDesc(2, None, DataNode), {}, None, None) MAXEXPONENT = IAttr( 'MAXEXPONENT', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) MAXLOC = IAttr( 'MAXLOC', True, False, False, ArgDesc(1, 2, DataNode), {"dim": DataNode, "mask": DataNode, "kind": DataNode, - "back": DataNode}) + "back": DataNode}, None, None) MAXVAL = IAttr( 'MAXVAL', True, False, False, ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}) + {"dim": DataNode, "mask": DataNode}, None, None) MERGE = IAttr( 'MERGE', True, True, False, - ArgDesc(3, 3, DataNode), {}) + ArgDesc(3, 3, DataNode), {}, None, None) MERGE_BITS = IAttr( 'MERGE_BITS', True, True, False, - ArgDesc(3, 3, DataNode), {}) + ArgDesc(3, 3, DataNode), {}, None, None) MIN = IAttr( 'MIN', True, True, False, - ArgDesc(2, None, DataNode), {}) + ArgDesc(2, None, DataNode), {}, None, None) MINEXPONENT = IAttr( 'MINEXPONENT', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) MINLOC = IAttr( 'MINLOC', True, False, False, ArgDesc(1, 2, DataNode), {"dim": DataNode, "mask": DataNode, "kind": DataNode, - "back": DataNode}) + "back": DataNode}, None, None) MINVAL = IAttr( 'MINVAL', True, False, False, ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}) + {"dim": DataNode, "mask": DataNode}, None, None) MOD = IAttr( 'MOD', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, None, None) MODULO = IAttr( 'MODULO', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, None, None) MOVE_ALLOC = IAttr( 'MOVE_ALLOC', False, False, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode, "errmsg": DataNode}) + ArgDesc(2, 2, DataNode), {"stat": DataNode, "errmsg": DataNode}, + None, None) MVBITS = IAttr( 'MVBITS', True, True, False, - ArgDesc(5, 5, DataNode), {}) + ArgDesc(5, 5, DataNode), {}, None, None) NEAREST = IAttr( 'NEAREST', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, None, None) NEW_LINE = IAttr( 'NEW_LINE', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) NINT = IAttr( 'NINT', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, None, None) NORM2 = IAttr( 'NORM2', True, False, False, - ArgDesc(1, 2, DataNode), {}) + ArgDesc(1, 2, DataNode), {}, None, None) NOT = IAttr( 'NOT', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) NULL = IAttr( 'NULL', True, False, False, - ArgDesc(0, 0, DataNode), {"mold": DataNode}) + ArgDesc(0, 0, DataNode), {"mold": DataNode}, None, None) NUM_IMAGES = IAttr( 'NUM_IMAGES', True, False, False, - ArgDesc(0, 1, DataNode), {}) + ArgDesc(0, 1, DataNode), {}, None, None) OUT_OF_RANGE = IAttr( 'OUT_OF_RANGE', True, True, False, - ArgDesc(2, 2, DataNode), {"round": DataNode}) + ArgDesc(2, 2, DataNode), {"round": DataNode}, None, None) PACK = IAttr( 'PACK', True, False, False, - ArgDesc(2, 2, DataNode), {"vector": DataNode}) + ArgDesc(2, 2, DataNode), {"vector": DataNode}, None, None) PARITY = IAttr( 'PARITY', True, False, False, - ArgDesc(1, 2, DataNode), {}) + ArgDesc(1, 2, DataNode), {}, None, None) POPCNT = IAttr( 'POPCNT', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) POPPAR = IAttr( 'POPPAR', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) PRECISION = IAttr( 'PRECISION', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) PRESENT = IAttr( 'PRESENT', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) PRODUCT = IAttr( 'PRODUCT', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, None, None) RADIX = IAttr( 'RADIX', True, False, True, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) RANDOM_INIT = IAttr( 'RANDOM_INIT', False, False, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, None, None) RANDOM_NUMBER = IAttr( 'RANDOM_NUMBER', False, False, False, - ArgDesc(1, 1, Reference), {}) + ArgDesc(1, 1, Reference), {}, None, None) RANDOM_SEED = IAttr( 'RANDOM_SEED', False, False, False, ArgDesc(0, 0, Reference), - {"size": DataNode, "put": DataNode, "Get": DataNode}) + {"size": DataNode, "put": DataNode, "Get": DataNode}, None, None) RANGE = IAttr( 'RANGE', True, False, True, - ArgDesc(1, 1, Reference), {}) + ArgDesc(1, 1, Reference), {}, None, None) RANK = IAttr( 'RANK', True, False, True, - ArgDesc(1, 1, Reference), {}) + ArgDesc(1, 1, Reference), {}, None, None) REAL = IAttr( 'REAL', True, True, False, - ArgDesc(1, 1, Reference), {"kind": DataNode}) + ArgDesc(1, 1, Reference), {"kind": DataNode}, None, None) REDUCE = IAttr( 'REDUCE', True, False, False, ArgDesc(2, 3, Reference), - {"mask": DataNode, "identity": DataNode, "ordered": DataNode}) + {"mask": DataNode, "identity": DataNode, "ordered": DataNode}, None, None) REPEAT = IAttr( 'REPEAT', True, False, False, - ArgDesc(2, 2, Reference), {}) + ArgDesc(2, 2, Reference), {}, None, None) RESHAPE = IAttr( 'RESHAPE', True, False, False, - ArgDesc(2, 2, Reference), {"pad": DataNode, "order": DataNode}) + ArgDesc(2, 2, Reference), {"pad": DataNode, "order": DataNode}, None, None) RRSPACING = IAttr( 'RRSPACING', True, True, False, - ArgDesc(1, 1, Reference), {}) + ArgDesc(1, 1, Reference), {}, None, None) SAME_TYPE_AS = IAttr( 'SAME_TYPE_AS', True, False, True, - ArgDesc(2, 2, Reference), {}) + ArgDesc(2, 2, Reference), {}, None, None) SCALE = IAttr( 'SCALE', True, True, False, - ArgDesc(2, 2, Reference), {}) + ArgDesc(2, 2, Reference), {}, None, None) SCAN = IAttr( 'SCAN', True, True, False, - ArgDesc(2, 2, Reference), {"back": DataNode, "kind": DataNode}) + ArgDesc(2, 2, Reference), {"back": DataNode, "kind": DataNode}, None, None) SELECTED_CHAR_KIND = IAttr( 'SELECTED_CHAR_KIND', True, False, False, - ArgDesc(1, 1, Reference), {}) + ArgDesc(1, 1, Reference), {}, None, None) SELECTED_INT_KIND = IAttr( 'SELECTED_INT_KIND', True, False, False, - ArgDesc(1, 1, Reference), {}) + ArgDesc(1, 1, Reference), {}, None, None) SELECTED_REAL_KIND = IAttr( 'SELECTED_REAL_KIND', True, False, False, ArgDesc(0, 0, Reference), - {"P": DataNode, "R": DataNode, "radix": DataNode}) + {"P": DataNode, "R": DataNode, "radix": DataNode}, None, None) SET_EXPONENT = IAttr( 'SET_EXPONENT', True, True, False, - ArgDesc(2, 2, Reference), {}) + ArgDesc(2, 2, Reference), {}, None, None) SHAPE = IAttr( 'SHAPE', True, False, True, - ArgDesc(1, 1, Reference), {"kind": DataNode}) + ArgDesc(1, 1, Reference), {"kind": DataNode}, None, None) SHIFTA = IAttr( 'SHIFTA', True, True, False, - ArgDesc(2, 2, Reference), {}) + ArgDesc(2, 2, Reference), {}, None, None) SHIFTL = IAttr( 'SHIFTL', True, True, False, - ArgDesc(2, 2, Reference), {}) + ArgDesc(2, 2, Reference), {}, None, None) SHIFTR = IAttr( 'SHIFTR', True, True, False, - ArgDesc(2, 2, Reference), {}) + ArgDesc(2, 2, Reference), {}, None, None) SIGN = IAttr( 'SIGN', True, True, False, - ArgDesc(2, 2, DataNode), {}) + ArgDesc(2, 2, DataNode), {}, None, None) SIN = IAttr( 'SIN', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) SINH = IAttr( 'SINH', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) SIZE = IAttr( 'SIZE', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, None, None) SPACING = IAttr( 'SPACING', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) SPREAD = IAttr( 'SPREAD', True, False, False, - ArgDesc(3, 3, DataNode), {}) + ArgDesc(3, 3, DataNode), {}, None, None) SQRT = IAttr( 'SQRT', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) STOPPED_IMAGES = IAttr( 'STOPPED_IMAGES', False, False, False, - ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}) + ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}, None, None) STORAGE_SIZE = IAttr( 'STORAGE_SIZE', True, False, True, - ArgDesc(1, 1, DataNode), {"kind": DataNode}) + ArgDesc(1, 1, DataNode), {"kind": DataNode}, None, None) SUM = IAttr( 'SUM', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, None, None) SYSTEM_CLOCK = IAttr( 'SYSTEM_CLOCK', False, False, False, ArgDesc(0, 0, DataNode), - {"count": DataNode, "count_rate": DataNode, "count_max": DataNode}) + {"count": DataNode, "count_rate": DataNode, "count_max": DataNode}, None, None) TAN = IAttr( 'TAN', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) TANH = IAttr( 'TANH', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) TEAM_IMAGE = IAttr( 'TEAM_IMAGE', True, False, False, - ArgDesc(0, 0, DataNode), {"team": DataNode}) + ArgDesc(0, 0, DataNode), {"team": DataNode}, None, None) THIS_IMAGE = IAttr( 'THIS_IMAGE', True, False, False, ArgDesc(0, 0, DataNode), - {"coarray": DataNode, "team": DataNode, "dim": DataNode}) + {"coarray": DataNode, "team": DataNode, "dim": DataNode}, None, None) TINY = IAttr( 'TINY', True, False, True, - ArgDesc(1, 1, (Reference, Literal)), {}) + ArgDesc(1, 1, (Reference, Literal)), {}, None, None) TRAILZ = IAttr( 'TRAILZ', True, True, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) TRANSFER = IAttr( 'TRANSFER', True, False, False, - ArgDesc(2, 2, DataNode), {"size": DataNode}) + ArgDesc(2, 2, DataNode), {"size": DataNode}, None, None) TRANSPOSE = IAttr( 'TRANSPOSE', True, False, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) TRIM = IAttr( 'TRIM', True, False, False, - ArgDesc(1, 1, DataNode), {}) + ArgDesc(1, 1, DataNode), {}, None, None) UBOUND = IAttr( 'UBOUND', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, None, None) UCOBOUND = IAttr( 'UCOBOUND', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, None, None) UNPACK = IAttr( 'UNPACK', True, False, False, - ArgDesc(3, 3, DataNode), {}) + ArgDesc(3, 3, DataNode), {}, None, None) VERIFY = IAttr( 'VERIFY', True, True, False, - ArgDesc(2, 2, DataNode), {"back": DataNode, "kind": DataNode}) + ArgDesc(2, 2, DataNode), {"back": DataNode, "kind": DataNode}, None, None) def __hash__(self): return hash(self.name) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 4f6a66c2c4..d950195d52 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -46,10 +46,12 @@ from psyclone.psyir.nodes import ( ArrayReference, Literal, Reference, Schedule, Assignment) -from psyclone.psyir.nodes.intrinsic_call import IntrinsicCall, IAttr +from psyclone.psyir.nodes.intrinsic_call import ( + IntrinsicCall, IAttr, _get_first_argument_type, + _get_first_argument_logical_kind_with_optional_dim) from psyclone.psyir.symbols import ( ArrayType, DataSymbol, INTEGER_TYPE, IntrinsicSymbol, REAL_TYPE, - BOOLEAN_TYPE, CHARACTER_TYPE) + BOOLEAN_TYPE, CHARACTER_TYPE, ScalarType, UnresolvedType) def test_intrinsic_enum(): @@ -579,3 +581,78 @@ def test_verify_intrinsic(fortran_reader, fortran_writer): "== 0) then" in result) assert ("if (verify(clname(ind1:ind2), '0123456789', kind=kind(1), " "back=.true.) == 0) then" in result) + + +def test_get_first_argument_type(fortran_reader): + '''Test the _get_first_argument_type helper function.''' + code = """subroutine x + integer :: a, b + a = 1 + b = ABS(a) + end subroutine x""" + psyir = fortran_reader.psyir_from_source(code) + abs_call = psyir.walk(IntrinsicCall)[0] + dtype = _get_first_argument_type(abs_call) + assert dtype.intrinsic == ScalarType.Intrinsic.INTEGER + assert dtype.precision == ScalarType.Precision.UNDEFINED + + +def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): + '''Test the _get_first_argument_logical_kind_with_optional_dim helper + function.''' + code = """subroutine x + logical, dimension(100,100) :: a + logical, dimension(100) :: b + logical :: c + c = ALL(a) + b = ALL(a, dim=1) + end subroutine x + """ + psyir = fortran_reader.psyir_from_source(code) + all_calls = psyir.walk(IntrinsicCall) + dtype = _get_first_argument_logical_kind_with_optional_dim(all_calls[0]) + assert dtype.intrinsic == ScalarType.Intrinsic.BOOLEAN + assert dtype.precision == ScalarType.Precision.UNDEFINED + dtype = _get_first_argument_logical_kind_with_optional_dim(all_calls[1]) + assert isinstance(dtype, ArrayType) + assert len(dtype.shape) == 1 + assert dtype.shape[0] == ArrayType.Extent.DEFERRED + assert dtype.datatype.intrinsic == ScalarType.Intrinsic.BOOLEAN + assert dtype.datatype.precision == ScalarType.Precision.UNDEFINED + + +@pytest.mark.parametrize("code, expected", [ + ("""subroutine x + complex(4) :: z4 + real :: result + result = aimag(z4) + end subroutine x""", + # AIMAG return type is UnresolvedType + lambda res: isinstance(res, UnresolvedType) + ), + ("""subroutine z + real*4 :: x + real :: y + y = AINT(x) + end subroutine z""", + # AINT return type is that of x here. + lambda res: (res.intrinsic == ScalarType.Intrinsic.REAL and + res.precision == 4) + ), + ("""subroutine z + real*4 :: x + real*8 :: y + y = AINT(x, kind=8) + end subroutine z""", + # AINT return type is REAL with kind 8. + lambda res: (res.intrinsic == ScalarType.Intrinsic.REAL and + isinstance(res.precision, Literal) and + res.precision.value == "8") + ), + ]) +def test_specific_return_types(fortran_reader, code, expected): + ''' Test the specific return types of each IntrinsicCall that has its own + defined return type function.''' + psyir = fortran_reader.psyir_from_source(code) + intrinsic = psyir.walk(IntrinsicCall)[0] + assert expected(intrinsic.intrinsic.return_type(intrinsic)) From 9bdb1edc56cc75ee59fc4c4ab0f9d3be447731f4 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Tue, 2 Sep 2025 10:46:42 +0100 Subject: [PATCH 02/41] [skip-ci] Initial version of intrinsic call extension --- src/psyclone/psyir/nodes/intrinsic_call.py | 40 +++++++++++++------ .../tests/psyir/nodes/intrinsic_call_test.py | 6 +-- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index ec0ab3b0cc..b8f57d284d 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -84,6 +84,7 @@ def _get_first_argument_type(node) -> DataType: ''' return node.arguments[0].datatype + # Anyone using this? def _get_first_argument_type_with_optional_kind(node) -> DataType: '''Helper function for the common IntrinsicCall case where the @@ -103,6 +104,7 @@ def _get_first_argument_type_with_optional_kind(node) -> DataType: return_type._precision = kind return return_type + def _get_first_argument_logical_kind_with_optional_dim(node) -> DataType: '''Helper function for the common IntrinsicCall case where the return type is a Scalar logical with the kind of the first argument, @@ -248,7 +250,7 @@ class Intrinsic(IAttr, Enum): ScalarType.Intrinsic.REAL, (node.arguments[node.argument_names.index("kind")] if "kind" not in node.argument_names else - arguments[0].datatype.precision)) + node.arguments[0].datatype.precision)) ), None) ANY = IAttr( 'ANY', True, False, False, @@ -846,7 +848,8 @@ class Intrinsic(IAttr, Enum): ArgDesc(1, 1, DataNode), {}, None, None) PRODUCT = IAttr( 'PRODUCT', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, None, None) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, + None, None) RADIX = IAttr( 'RADIX', True, False, True, ArgDesc(1, 1, DataNode), {}, None, None) @@ -872,13 +875,15 @@ class Intrinsic(IAttr, Enum): REDUCE = IAttr( 'REDUCE', True, False, False, ArgDesc(2, 3, Reference), - {"mask": DataNode, "identity": DataNode, "ordered": DataNode}, None, None) + {"mask": DataNode, "identity": DataNode, "ordered": DataNode}, + None, None) REPEAT = IAttr( 'REPEAT', True, False, False, ArgDesc(2, 2, Reference), {}, None, None) RESHAPE = IAttr( 'RESHAPE', True, False, False, - ArgDesc(2, 2, Reference), {"pad": DataNode, "order": DataNode}, None, None) + ArgDesc(2, 2, Reference), {"pad": DataNode, "order": DataNode}, + None, None) RRSPACING = IAttr( 'RRSPACING', True, True, False, ArgDesc(1, 1, Reference), {}, None, None) @@ -890,7 +895,8 @@ class Intrinsic(IAttr, Enum): ArgDesc(2, 2, Reference), {}, None, None) SCAN = IAttr( 'SCAN', True, True, False, - ArgDesc(2, 2, Reference), {"back": DataNode, "kind": DataNode}, None, None) + ArgDesc(2, 2, Reference), {"back": DataNode, "kind": DataNode}, + None, None) SELECTED_CHAR_KIND = IAttr( 'SELECTED_CHAR_KIND', True, False, False, ArgDesc(1, 1, Reference), {}, None, None) @@ -927,7 +933,8 @@ class Intrinsic(IAttr, Enum): ArgDesc(1, 1, DataNode), {}, None, None) SIZE = IAttr( 'SIZE', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, None, None) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, + None, None) SPACING = IAttr( 'SPACING', True, True, False, ArgDesc(1, 1, DataNode), {}, None, None) @@ -939,17 +946,20 @@ class Intrinsic(IAttr, Enum): ArgDesc(1, 1, DataNode), {}, None, None) STOPPED_IMAGES = IAttr( 'STOPPED_IMAGES', False, False, False, - ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}, None, None) + ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}, + None, None) STORAGE_SIZE = IAttr( 'STORAGE_SIZE', True, False, True, ArgDesc(1, 1, DataNode), {"kind": DataNode}, None, None) SUM = IAttr( 'SUM', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, None, None) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, + None, None) SYSTEM_CLOCK = IAttr( 'SYSTEM_CLOCK', False, False, False, ArgDesc(0, 0, DataNode), - {"count": DataNode, "count_rate": DataNode, "count_max": DataNode}, None, None) + {"count": DataNode, "count_rate": DataNode, "count_max": DataNode}, + None, None) TAN = IAttr( 'TAN', True, True, False, ArgDesc(1, 1, DataNode), {}, None, None) @@ -962,7 +972,8 @@ class Intrinsic(IAttr, Enum): THIS_IMAGE = IAttr( 'THIS_IMAGE', True, False, False, ArgDesc(0, 0, DataNode), - {"coarray": DataNode, "team": DataNode, "dim": DataNode}, None, None) + {"coarray": DataNode, "team": DataNode, "dim": DataNode}, + None, None) TINY = IAttr( 'TINY', True, False, True, ArgDesc(1, 1, (Reference, Literal)), {}, None, None) @@ -980,16 +991,19 @@ class Intrinsic(IAttr, Enum): ArgDesc(1, 1, DataNode), {}, None, None) UBOUND = IAttr( 'UBOUND', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, None, None) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, + None, None) UCOBOUND = IAttr( 'UCOBOUND', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, None, None) + ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, + None, None) UNPACK = IAttr( 'UNPACK', True, False, False, ArgDesc(3, 3, DataNode), {}, None, None) VERIFY = IAttr( 'VERIFY', True, True, False, - ArgDesc(2, 2, DataNode), {"back": DataNode, "kind": DataNode}, None, None) + ArgDesc(2, 2, DataNode), {"back": DataNode, "kind": DataNode}, + None, None) def __hash__(self): return hash(self.name) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index d950195d52..2cea2ca76d 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -629,7 +629,7 @@ def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): end subroutine x""", # AIMAG return type is UnresolvedType lambda res: isinstance(res, UnresolvedType) - ), + ), ("""subroutine z real*4 :: x real :: y @@ -638,7 +638,7 @@ def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): # AINT return type is that of x here. lambda res: (res.intrinsic == ScalarType.Intrinsic.REAL and res.precision == 4) - ), + ), ("""subroutine z real*4 :: x real*8 :: y @@ -648,7 +648,7 @@ def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): lambda res: (res.intrinsic == ScalarType.Intrinsic.REAL and isinstance(res.precision, Literal) and res.precision.value == "8") - ), + ), ]) def test_specific_return_types(fortran_reader, code, expected): ''' Test the specific return types of each IntrinsicCall that has its own From 1293219c860d8a5af9b556370267a973b05488f1 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Tue, 2 Sep 2025 16:41:20 +0100 Subject: [PATCH 03/41] [skip-ci] Added more intrisic return types and applied black formatter --- src/psyclone/psyir/nodes/intrinsic_call.py | 2872 +++++++++++++---- .../tests/psyir/nodes/intrinsic_call_test.py | 974 ++++-- 2 files changed, 2976 insertions(+), 870 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index b8f57d284d..588375edc2 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -36,7 +36,7 @@ # Modified: S. Siso, STFC Daresbury Lab # ----------------------------------------------------------------------------- -''' This module contains the IntrinsicCall node implementation.''' +"""This module contains the IntrinsicCall node implementation.""" from collections import namedtuple from collections.abc import Iterable @@ -49,17 +49,25 @@ from psyclone.psyir.nodes.reference import Reference from psyclone.psyir.symbols import IntrinsicSymbol from psyclone.psyir.symbols.datatypes import ( - CHARACTER_TYPE, BOOLEAN_TYPE, INTEGER_TYPE, - REAL_DOUBLE_TYPE, REAL8_TYPE, REAL_TYPE, - DataType, ArrayType, ScalarType, UnresolvedType + CHARACTER_TYPE, + BOOLEAN_TYPE, + INTEGER_TYPE, + REAL_DOUBLE_TYPE, + REAL8_TYPE, + REAL_TYPE, + DataType, + ArrayType, + ScalarType, + UnresolvedType, ) # pylint: disable=too-many-branches # Named tuple for describing the attributes of each intrinsic IAttr = namedtuple( - 'IAttr', 'name is_pure is_elemental is_inquiry required_args optional_args' - ' return_type reference_accesses' + "IAttr", + "name is_pure is_elemental is_inquiry required_args optional_args" + " return_type reference_accesses", ) # Alternatively we could use an Enum to decrive the intrinsic types # IntrinsicType = Enum('IntrinsicType', @@ -70,24 +78,23 @@ # Named tuple for describing the properties of the required arguments to # a particular intrinsic. If there's no limit on the number of arguments # then `max_count` will be None. -ArgDesc = namedtuple('ArgDesc', 'min_count max_count types') +ArgDesc = namedtuple("ArgDesc", "min_count max_count types") def _get_first_argument_type(node) -> DataType: - '''Helper function for the common IntrinsicCall case where + """Helper function for the common IntrinsicCall case where the return type matches exactly the datatype of the first argument. :param node: The IntrinsicCall whose return type to compute. :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` :returns: the datatype of the first argument of the IntrinsicCall. - ''' + """ return node.arguments[0].datatype -# Anyone using this? def _get_first_argument_type_with_optional_kind(node) -> DataType: - '''Helper function for the common IntrinsicCall case where the + """Helper function for the common IntrinsicCall case where the return type is the Intrinsic of the first argument, with an optional kind parameter which may override the precision. @@ -95,7 +102,7 @@ def _get_first_argument_type_with_optional_kind(node) -> DataType: :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` :returns: the datatype of the first argument of the IntrinsicCall. - ''' + """ if "kind" not in node.argument_names: return node.arguments[0].datatype else: @@ -105,8 +112,53 @@ def _get_first_argument_type_with_optional_kind(node) -> DataType: return return_type +def _get_first_argument_intrinsic_with_optional_kind_and_dim(node) -> DataType: + """Helper function for IntrinsicCalls like MAXLOC where they have optional + Kind and Dim options but the intrinsic is that of the first argument. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + if "kind" in node.argument_names: + dtype = ScalarType( + node.arguments[0].datatype.datatype.intrinsic, + node.arguments[node.argument_names.index("kind")], + ) + else: + # PSyclone has the UNDEFINED Precision as the default kind for all + # supported inbuilt datatypes. + dtype = ScalarType( + node.arguments[0].datatype.intrinsic, + ScalarType.Precision.UNDEFINED, + ) + if "dim" not in node.argument_names: + return ArrayType( + dtype, + [ + ArrayType.ArrayBounds( + Literal("1", INTEGER_TYPE), + Literal( + str(len(node.arguments[0].datatype.shape)), + INTEGER_TYPE, + ), + ) + ], + ) + # Always have dim from here. + # If array has rank 1, the result is scalar. + arg = node.arguments[0] + shape = arg.datatype.shape + if len(shape) == 1: + return dtype + # For now we don't attempt to work out the shape. + new_shape = [ArrayType.Extent.DEFERRED] * (len(shape) - 1) + return ArrayType(dtype, new_shape) + + def _get_first_argument_logical_kind_with_optional_dim(node) -> DataType: - '''Helper function for the common IntrinsicCall case where the + """Helper function for the common IntrinsicCall case where the return type is a Scalar logical with the kind of the first argument, unless an option dim parameter is given in which case an array with rank is given instead. @@ -115,9 +167,62 @@ def _get_first_argument_logical_kind_with_optional_dim(node) -> DataType: :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` :returns: the computed datatype for the IntrinsicCall. - ''' - dtype = ScalarType(ScalarType.Intrinsic.BOOLEAN, - node.arguments[0].datatype.precision) + """ + dtype = ScalarType( + ScalarType.Intrinsic.BOOLEAN, node.arguments[0].datatype.precision + ) + if "dim" not in node.argument_names: + return dtype + else: + # If dim is given then this should return an array, but we + # don't necessarily know the dimensions of the resulting array + # at compile time. It will have one fewer dimension than the + # input. + arg = node.arguments[0] + shape = arg.datatype.shape + if len(shape) == 1: + return dtype + # For now we don't attempt to work out the shape. + new_shape = [ArrayType.Extent.DEFERRED] * (len(shape) - 1) + return ArrayType(dtype, new_shape) + + +def _get_integer_with_optional_kind(node) -> DataType: + """Helper function for the common case where the return type is a + Scalar integer with an optional kind argument. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + return ( + ScalarType( + ScalarType.Intrinsic.INTEGER, + node.arguments[node.argument_names.index("kind")], + ) + if "kind" in node.argument_names + else INTEGER_TYPE + ) + + +def _get_integer_of_kind_with_optional_dim(node) -> DataType: + """Helper function for a type of Integer with optional dim and + kind options. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + dtype = ScalarType( + ScalarType.Intrinsic.INTEGER, + ( + ScalarType.Precision.UNDEFINED + if "kind" not in node.argument_names + else node.arguments[node.argument_names.index("kind")] + ), + ) if "dim" not in node.argument_names: return dtype else: @@ -131,12 +236,170 @@ def _get_first_argument_logical_kind_with_optional_dim(node) -> DataType: return dtype else: # For now we don't attempt to work out the shape. - new_shape = [ArrayType.Extent.DEFERRED]*(len(shape)-1) + new_shape = [ArrayType.Extent.DEFERRED] * (len(shape) - 1) return ArrayType(dtype, new_shape) +def _get_real_with_argone_kind(node) -> DataType: + """Helper function for the common IntrinsicCall case where the + return type is a Scalar REAL with the kind of the first argument. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + return ScalarType( + ScalarType.Intrinsic.REAL, node.arguments[0].datatype.precision + ) + + +def _get_real_with_x_kind(node) -> DataType: + """Helper function for the BESSEL_.N cases, where the return type is + a Scalar REAL with the kind of the X argument (the final argument). + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + return ScalarType( + ScalarType.Intrinsic.REAL, node.arguments[-1].datatype.precision + ) + + +def _findloc_return_type(node) -> DataType: + """Helper function for the FINDLOC case. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + if "kind" in node.argument_names: + dtype = ScalarType( + node.arguments[0].intrinsic, + node.arguments[node.argument_names.index("kind")], + ) + else: + dtype = node.arguments[0].datatype.copy() + if "dim" in node.argument_names: + if len(node.arguments.shape) == 1: + return dtype + else: + # We can't get the sizes correct since we don't know + # dim, so use deferred. + return ArrayType( + dtype, + [ArrayType.Extent.DEFFERED] + * (len(node.arguemtns[0].shape) - 1), + ) + else: + return ArrayType( + dtype, + [ + ArrayType.ArrayBounds( + Literal("1", INTEGER_TYPE), + Literal( + str(len(node.arguments[0].datatype.shape)), + INTEGER_TYPE, + ), + ) + ], + ) + + +def _int_return_type(node) -> DataType: + """Helper function for the INT case. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + if "kind" in node.argument_names: + dtype = ScalarType( + ScalarType.Intrinsic.INTEGER, + node.arguments[node.argument_names.index("kind")], + ) + else: + dtype = INTEGER_TYPE + + if isinstance(node.arguments[0].datatype, ArrayType): + return ArrayType( + dtype, + [ + ( + index.copy() + if not isinstance(index, ArrayType.ArrayBounds) + else ArrayType.ArrayBounds(index.lower, index.upper) + ) + for index in node.arguments[0].datatype.shape + ], + ) + else: + return dtype + + +def _iparity_return_type(node) -> DataType: + """Helper function for the IPARITY case. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + dtype = ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision, + ) + if len(node.arguments) == 1 or ( + len(node.arguments) == 2 and "mask" in node.argument_names + ): + return dtype + else: + # We have a dimension specified. We don't know the resultant shape + # in any detail as its dependent on the value of dim + return ArrayType( + dtype, + [ArrayType.Extent.DEFERRED] + * (len(node.arguments[0].datatype.shape) - 1), + ) + + +def _get_bound_function_return_type(node) -> DataType: + """Helper function for the return types of functions like LBOUND and + LCOBOUND etc. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + if "kind" in node.argument_names: + dtype = ScalarType( + ScalarType.Intrinsic.INTEGER, + node.arguments[node.argument_names.index("kind")], + ) + else: + dtype = INTEGER_TYPE + if "dim" in node.argument_names: + return dtype + return ArrayType( + dtype, + [ + ArrayType.ArrayBounds( + Literal("1", INTEGER_TYPE), + Literal( + str(len(node.arguments[0].datatype.shape)), INTEGER_TYPE + ), + ) + ], + ) + + class IntrinsicCall(Call): - ''' Node representing a call to an intrinsic routine (function or + """Node representing a call to an intrinsic routine (function or subroutine). This can be found as a standalone statement or an expression. @@ -147,7 +410,8 @@ class IntrinsicCall(Call): :raises TypeError: if the 'intrinsic' argument is not an Intrinsic type. - ''' + """ + # Textual description of the node. _children_valid_format = "[DataNode]*" _text_name = "IntrinsicCall" @@ -158,7 +422,7 @@ class IntrinsicCall(Call): _symbol_type = IntrinsicSymbol class Intrinsic(IAttr, Enum): - ''' Enum of all intrinsics with their attributes as values using the + """Enum of all intrinsics with their attributes as values using the IAttr namedtuple format: NAME = IAttr(name, is_pure, is_elemental, is_inquiry, @@ -169,841 +433,2085 @@ class Intrinsic(IAttr, Enum): Enum must have a different value, and without the name that would not be guaranteed. - ''' + """ + # Fortran special-case statements (technically not Fortran intrinsics # but in PSyIR they are represented as Intrinsics) # TODO 3060 reference_accesses ALLOCATE = IAttr( - 'ALLOCATE', False, False, False, + "ALLOCATE", + False, + False, + False, ArgDesc(1, None, Reference), - {"mold": Reference, "source": Reference, "stat": Reference, - "errmsg": Reference}, None, None) + { + "mold": Reference, + "source": Reference, + "stat": Reference, + "errmsg": Reference, + }, + None, + None, + ) DEALLOCATE = IAttr( - 'DEALLOCATE', False, False, False, - ArgDesc(1, None, Reference), {"stat": Reference}, - None, None) + "DEALLOCATE", + False, + False, + False, + ArgDesc(1, None, Reference), + {"stat": Reference}, + None, + None, + ) NULLIFY = IAttr( - 'NULLIFY', False, False, False, - ArgDesc(1, None, Reference), {}, None, None) + "NULLIFY", + False, + False, + False, + ArgDesc(1, None, Reference), + {}, + None, + None, + ) # Fortran Intrinsics (from Fortran 2018 standard table 16.1) ABS = IAttr( - 'ABS', True, True, False, - ArgDesc(1, 1, DataNode), {}, + "ABS", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, # TODO 1590 Complex conversion unsupported. _get_first_argument_type, - None) + None, + ) ACHAR = IAttr( - 'ACHAR', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, - CHARACTER_TYPE, None) + "ACHAR", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, + CHARACTER_TYPE, + None, + ) ACOS = IAttr( - 'ACOS', True, True, False, - ArgDesc(1, 1, DataNode), {}, - _get_first_argument_type, None) + "ACOS", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) ACOSH = IAttr( - 'ACOSH', True, True, False, - ArgDesc(1, 1, DataNode), {}, - _get_first_argument_type, None) + "ACOSH", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) ADJUSTL = IAttr( - 'ADJUSTL', True, True, False, - ArgDesc(1, 1, DataNode), {}, + "ADJUSTL", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, # TODO 2612 This may be more complex if we support character len _get_first_argument_type, - None) + None, + ) ADJUSTR = IAttr( - 'ADJUSTR', True, True, False, - ArgDesc(1, 1, DataNode), {}, + "ADJUSTR", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, # TODO 2612 This may be more complex if we support character len _get_first_argument_type, - None) + None, + ) AIMAG = IAttr( - 'AIMAG', True, True, False, - ArgDesc(1, 1, DataNode), {}, + "AIMAG", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, # TODO #1590 Complex numbers' precision unsupported. lambda node: UnresolvedType(), - None) + None, + ) AINT = IAttr( - 'AINT', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, + "AINT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, lambda node: ( ScalarType( ScalarType.Intrinsic.REAL, - (node.arguments[node.argument_names.index("kind")] - if "kind" in node.argument_names else - node.arguments[0].datatype.precision)) - ), None) + ( + node.arguments[node.argument_names.index("kind")] + if "kind" in node.argument_names + else node.arguments[0].datatype.precision + ), + ) + ), + None, + ) ALL = IAttr( - 'ALL', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode}, + "ALL", + True, + False, + False, + ArgDesc(1, 1, DataNode), + {"dim": DataNode}, _get_first_argument_logical_kind_with_optional_dim, - None) + None, + ) ALLOCATED = IAttr( - 'ALLOCATED', True, False, True, - ArgDesc(1, 1, DataNode), {}, - BOOLEAN_TYPE, None) + "ALLOCATED", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + BOOLEAN_TYPE, + None, + ) ANINT = IAttr( - 'ANINT', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, + "ANINT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, lambda node: ( ScalarType( ScalarType.Intrinsic.REAL, - (node.arguments[node.argument_names.index("kind")] - if "kind" not in node.argument_names else - node.arguments[0].datatype.precision)) - ), None) + ( + node.arguments[node.argument_names.index("kind")] + if "kind" not in node.argument_names + else node.arguments[0].datatype.precision + ), + ) + ), + None, + ) ANY = IAttr( - 'ANY', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode}, - # FIXME Return type - None, None) + "ANY", + True, + False, + False, + ArgDesc(1, 1, DataNode), + {"dim": DataNode}, + _get_first_argument_logical_kind_with_optional_dim, + None, + ) ASIN = IAttr( - 'ASIN', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "ASIN", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) ASINH = IAttr( - 'ASINH', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "ASINH", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) ASSOCIATED = IAttr( - 'ASSOCIATED', False, False, True, - ArgDesc(1, 1, DataNode), {"target": DataNode}, - BOOLEAN_TYPE, None) + "ASSOCIATED", + False, + False, + True, + ArgDesc(1, 1, DataNode), + {"target": DataNode}, + BOOLEAN_TYPE, + None, + ) ATAN = IAttr( - 'ATAN', True, True, False, - ArgDesc(1, 2, DataNode), {}, - # FIXME Return type - None, None) + "ATAN", + True, + True, + False, + ArgDesc(1, 2, DataNode), + {}, + # N. B. If this has 2 arguments then the return value + # is the of the second argument, however the standard defines + # the type and kind type of both arguments must be the same. + _get_first_argument_type, + None, + ) ATAN2 = IAttr( - 'ATAN2', True, True, False, - ArgDesc(2, 2, DataNode), {}, - # FIXME Return type - None, None) + "ATAN2", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + _get_first_argument_type, + None, + ) ATANH = IAttr( - 'ATANH', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "ATANH", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) ATOMIC_ADD = IAttr( - 'ATOMIC_ADD', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_ADD", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_AND = IAttr( - 'ATOMIC_AND', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_AND", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_CAS = IAttr( - 'ATOMIC_CAS', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_CAS", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_DEFINE = IAttr( - 'ATOMIC_DEFINE', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_DEFINE", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_FETCH_ADD = IAttr( - 'ATOMIC_FETCH_ADD', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_FETCH_ADD", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_FETCH_AND = IAttr( - 'ATOMIC_FETCH_AND', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_FETCH_AND", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_FETCH_OR = IAttr( - 'ATOMIC_FETCH_OR', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_FETCH_OR", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_FETCH_XOR = IAttr( - 'ATOMIC_FETCH_XOR', True, True, False, - ArgDesc(3, 3, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_FETCH_XOR", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_OR = IAttr( - 'ATOMIC_OR', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_OR", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_REF = IAttr( - 'ATOMIC_REF', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_REF", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) ATOMIC_XOR = IAttr( - 'ATOMIC_XOR', True, True, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "ATOMIC_XOR", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) BESSEL_J0 = IAttr( - 'BESSEL_J0', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "BESSEL_J0", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_real_with_argone_kind, + None, + ) BESSEL_J1 = IAttr( - 'BESSEL_J1', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "BESSEL_J1", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_real_with_argone_kind, + None, + ) BESSEL_JN = IAttr( - 'BESSEL_JN', True, None, False, - ArgDesc(2, 3, DataNode), {}, - # FIXME Return type - None, None) + "BESSEL_JN", + True, + None, + False, + ArgDesc(2, 3, DataNode), + {}, + _get_real_with_x_kind, + None, + ) BESSEL_Y0 = IAttr( - 'BESSEL_Y0', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "BESSEL_Y0", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_real_with_argone_kind, + None, + ) BESSEL_Y1 = IAttr( - 'BESSEL_Y1', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "BESSEL_Y1", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_real_with_argone_kind, + None, + ) BESSEL_YN = IAttr( - 'BESSEL_YN', True, None, False, - ArgDesc(2, 3, DataNode), {}, - # FIXME Return type - None, None) + "BESSEL_YN", + True, + None, + False, + ArgDesc(2, 3, DataNode), + {}, + _get_real_with_x_kind, + None, + ) BGE = IAttr( - 'BGE', True, True, False, - ArgDesc(2, 2, DataNode), {}, - BOOLEAN_TYPE, None) + "BGE", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + BOOLEAN_TYPE, + None, + ) BGT = IAttr( - 'BGT', True, True, False, - ArgDesc(2, 2, DataNode), {}, - BOOLEAN_TYPE, None) + "BGT", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + BOOLEAN_TYPE, + None, + ) BIT_SIZE = IAttr( - 'BIT_SIZE', True, False, True, - ArgDesc(1, 1, DataNode), {}, - INTEGER_TYPE, None) + "BIT_SIZE", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + INTEGER_TYPE, + None, + ) BLE = IAttr( - 'BLE', True, True, False, - ArgDesc(2, 2, DataNode), {}, - BOOLEAN_TYPE, None) + "BLE", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + BOOLEAN_TYPE, + None, + ) BLT = IAttr( - 'BLT', True, True, False, - ArgDesc(2, 2, DataNode), {}, - BOOLEAN_TYPE, None) + "BLT", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + BOOLEAN_TYPE, + None, + ) BTEST = IAttr( - 'BTEST', True, True, False, - ArgDesc(2, 2, DataNode), {}, - BOOLEAN_TYPE, None) + "BTEST", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + BOOLEAN_TYPE, + None, + ) CEILING = IAttr( - 'CEILING', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, - # FIXME Return type - None, None) + "CEILING", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) CHAR = IAttr( - 'CHAR', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, - # FIXME Return type - None, None) + "CHAR", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, + CHARACTER_TYPE, + None, + ) CMPLX = IAttr( - 'CMPLX', True, True, False, - ArgDesc(1, 1, DataNode), {"Y": DataNode, "kind": DataNode}, - # FIXME Return type - None, None) + "CMPLX", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"Y": DataNode, "kind": DataNode}, + # TODO #1590 Complex numbers unsupported. + lambda node: UnresolvedType(), + None, + ) CO_BROADCAST = IAttr( - 'CO_BROADCAST', True, False, False, - ArgDesc(1, 2, DataNode), {"stat": DataNode, "errmsg": DataNode}, - None, None) + "CO_BROADCAST", + True, + False, + False, + ArgDesc(1, 2, DataNode), + {"stat": DataNode, "errmsg": DataNode}, + None, + None, + ) CO_MAX = IAttr( - 'CO_MAX', True, False, False, + "CO_MAX", + True, + False, + False, ArgDesc(1, 1, DataNode), {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, None) + None, + None, + ) CO_MIN = IAttr( - 'CO_MIN', True, False, False, + "CO_MIN", + True, + False, + False, ArgDesc(1, 1, DataNode), {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, None) + None, + None, + ) CO_REDUCE = IAttr( - 'CO_REDUCE', True, False, False, + "CO_REDUCE", + True, + False, + False, ArgDesc(1, 2, DataNode), {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, None) + None, + None, + ) CO_SUM = IAttr( - 'CO_SUM', True, False, False, + "CO_SUM", + True, + False, + False, ArgDesc(1, 1, DataNode), {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, None) + None, + None, + ) COMMAND_ARGUMENT_COUNT = IAttr( - 'COMMAND_ARGUMENT_COUNT', True, False, False, - ArgDesc(0, 0, None), {}, - INTEGER_TYPE, None) + "COMMAND_ARGUMENT_COUNT", + True, + False, + False, + ArgDesc(0, 0, None), + {}, + INTEGER_TYPE, + None, + ) CONJG = IAttr( - 'CONJG', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "CONJG", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + # TODO #1590 Complex numbers unsupported. + lambda node: UnresolvedType(), + None, + ) COS = IAttr( - 'COS', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "COS", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) COSH = IAttr( - 'COSH', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "COSH", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) COSHAPE = IAttr( - 'COSHAPE', True, False, True, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, + "COSHAPE", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, # FIXME Return type - None, None) + lambda node: ArrayType( + ScalarType( + ScalarType.Intrinsic.INTEGER, + ( + node.arguments[0].datatype.precision + if "kind" not in node.argument_names + else node.arguments[node.argument_names.index("kind")] + ), + ), + [ + ( + index.copy() + if not isinstance(index, ArrayType.ArrayBounds) + else ArrayType.ArrayBounds(index.lower, index.upper) + ) + for index in node.arguments[0].datatype.shape + ], + ), + None, + ) COUNT = IAttr( - 'COUNT', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, - # FIXME Return type - None, None) + "COUNT", + True, + False, + False, + ArgDesc(1, 1, DataNode), + {"dim": DataNode, "kind": DataNode}, + _get_integer_of_kind_with_optional_dim, + None, + ) CPU_TIME = IAttr( - 'CPU_TIME', False, False, False, - ArgDesc(1, 1, DataNode), {}, - None, None) + "CPU_TIME", + False, + False, + False, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) CSHIFT = IAttr( - 'CSHIFT', True, False, False, - ArgDesc(2, 2, DataNode), {"dim": DataNode}, - # FIXME Return type - None, None) + "CSHIFT", + True, + False, + False, + ArgDesc(2, 2, DataNode), + {"dim": DataNode}, + _get_first_argument_type, # FIXME Wait on Sergi reply + None, + ) DATE_AND_TIME = IAttr( - 'DATE_AND_TIME', False, False, False, + "DATE_AND_TIME", + False, + False, + False, ArgDesc(0, 0, DataNode), - {"date": DataNode, "time": DataNode, - "zone": DataNode, "values": DataNode}, - None, None) + { + "date": DataNode, + "time": DataNode, + "zone": DataNode, + "values": DataNode, + }, + None, + None, + ) DBLE = IAttr( - 'DBLE', True, True, False, - ArgDesc(1, 1, DataNode), {}, - REAL_DOUBLE_TYPE, None) + "DBLE", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + REAL_DOUBLE_TYPE, + None, + ) DIGITS = IAttr( - 'DIGITS', True, False, True, - ArgDesc(1, 1, DataNode), {}, - INTEGER_TYPE, None) + "DIGITS", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + INTEGER_TYPE, + None, + ) DIM = IAttr( - 'DIM', True, True, False, - ArgDesc(2, 2, DataNode), {}, - # FIXME Return type - None, None) + "DIM", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + _get_first_argument_type, + None, + ) DOT_PRODUCT = IAttr( - 'DOT_PRODUCT', True, False, False, - ArgDesc(2, 2, DataNode), {}, - # FIXME Return type - None, None) + "DOT_PRODUCT", + True, + False, + False, + ArgDesc(2, 2, DataNode), + {}, + lambda node: ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision, + ), + None, + ) DPROD = IAttr( - 'DPROD', True, True, False, - ArgDesc(2, 2, DataNode), {}, - REAL8_TYPE, None) + "DPROD", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + REAL8_TYPE, + None, + ) DSHIFTL = IAttr( - 'DSHIFTL', True, True, False, - ArgDesc(3, 3, DataNode), {}, - # FIXME Return type - None, None) + "DSHIFTL", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {}, + lambda node: ( + node.arguments[0].datatype.copy() + if not isinstance(node.arguments[0], Literal) + else node.arguments[1].datatype.copy() + ), + None, + ) DSHIFTR = IAttr( - 'DSHIFTR', True, True, False, - ArgDesc(3, 3, DataNode), {}, - # FIXME Return type - None, None) + "DSHIFTR", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {}, + lambda node: ( + node.arguments[0].datatype.copy() + if not isinstance(node.arguments[0], Literal) + else node.arguments[1].datatype.copy() + ), + None, + ) EOSHIFT = IAttr( - 'EOSHIFT', True, False, False, - ArgDesc(2, 2, DataNode), {"boundary": DataNode, "dim": DataNode}, - # FIXME Return type - None, None) + "EOSHIFT", + True, + False, + False, + ArgDesc(2, 2, DataNode), + {"boundary": DataNode, "dim": DataNode}, + _get_first_argument_type, # FIXME Wait for Sergi reply. + None, + ) EPSILON = IAttr( - 'EPSILON', True, False, True, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "EPSILON", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) ERF = IAttr( - 'ERF', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "ERF", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_real_with_argone_kind, + None, + ) ERFC = IAttr( - 'ERFC', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "ERFC", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_real_with_argone_kind, + None, + ) ERFC_SCALED = IAttr( - 'ERFC_SCALED', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "ERFC_SCALED", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_real_with_argone_kind, + None, + ) EVENT_QUERY = IAttr( - 'EVENT_QUERY', False, False, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode}, - None, None) + "EVENT_QUERY", + False, + False, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode}, + None, + None, + ) EXECUTE_COMMAND_LINE = IAttr( - 'EXECUTE_COMMAND_LINE', False, False, False, + "EXECUTE_COMMAND_LINE", + False, + False, + False, ArgDesc(2, 2, DataNode), - {"wait": DataNode, "exitstat": DataNode, - "cmdstat": DataNode, "cmdmsg": DataNode}, - None, None) + { + "wait": DataNode, + "exitstat": DataNode, + "cmdstat": DataNode, + "cmdmsg": DataNode, + }, + None, + None, + ) EXP = IAttr( - 'EXP', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "EXP", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) EXPONENT = IAttr( - 'EXPONENT', True, True, False, - ArgDesc(1, 1, DataNode), {}, - INTEGER_TYPE, None) + "EXPONENT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + INTEGER_TYPE, + None, + ) EXTENDS_TYPE_OF = IAttr( - 'EXTENDS_TYPE_OF', True, False, True, - ArgDesc(2, 2, DataNode), {}, - BOOLEAN_TYPE, None) + "EXTENDS_TYPE_OF", + True, + False, + True, + ArgDesc(2, 2, DataNode), + {}, + BOOLEAN_TYPE, + None, + ) FAILED_IMAGES = IAttr( - 'FAILED_IMAGES', False, False, False, - ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}, - # FIXME Return type - None, None) + "FAILED_IMAGES", + False, + False, + False, + ArgDesc(0, 0, DataNode), + {"team": DataNode, "kind": DataNode}, + lambda node: ArrayType( + ScalarType( + ScalarType.Intrinsic.INTEGER, + ( + node.arguments[node.argument_names.index("kind")] + if "kind" in node.argument_names + else ScalarType.Precision.UNDEFINED + ), + ), + [ArrayType.Extent.DEFERRED], + ), + None, + ) FINDLOC = IAttr( - 'FINDLOC', True, False, False, + "FINDLOC", + True, + False, + False, ArgDesc(2, 3, DataNode), {"mask": DataNode, "kind": DataNode, "back": DataNode}, - # FIXME Return type - None, None) + _findloc_return_type, + None, + ) FLOAT = IAttr( - 'FLOAT', True, True, False, - ArgDesc(1, 1, DataNode), {}, - REAL_TYPE, None) + "FLOAT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + REAL_TYPE, + None, + ) FLOOR = IAttr( - 'FLOOR', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, - # FIXME Return type - None, None) + "FLOOR", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) FRACTION = IAttr( - 'FRACTION', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "FRACTION", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) GAMMA = IAttr( - 'GAMMA', True, True, False, - ArgDesc(1, 1, DataNode), {}, - # FIXME Return type - None, None) + "GAMMA", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None, + ) GET_COMMAND = IAttr( - 'GET_COMMAND', False, False, False, + "GET_COMMAND", + False, + False, + False, ArgDesc(0, 0, DataNode), - {"command": DataNode, "length": DataNode, - "status": DataNode, "errmsg": DataNode}, - None, None) + { + "command": DataNode, + "length": DataNode, + "status": DataNode, + "errmsg": DataNode, + }, + None, + None, + ) GET_COMMAND_ARGUMENT = IAttr( - 'GET_COMMAND_ARGUMENT', False, False, False, + "GET_COMMAND_ARGUMENT", + False, + False, + False, ArgDesc(1, 1, DataNode), - {"value": DataNode, "length": DataNode, - "status": DataNode, "errmsg": DataNode}, - None, None) + { + "value": DataNode, + "length": DataNode, + "status": DataNode, + "errmsg": DataNode, + }, + None, + None, + ) GET_ENVIRONMENT_VARIABLE = IAttr( - 'GET_ENVIRONMENT_VARIABLE', False, False, False, + "GET_ENVIRONMENT_VARIABLE", + False, + False, + False, ArgDesc(1, 1, DataNode), - {"value": DataNode, "length": DataNode, "status": DataNode, - "trim_name": DataNode, "errmsg": DataNode}, - None, None) + { + "value": DataNode, + "length": DataNode, + "status": DataNode, + "trim_name": DataNode, + "errmsg": DataNode, + }, + None, + None, + ) GET_TEAM = IAttr( - 'GET_TEAM', True, False, False, - ArgDesc(0, 0, DataNode), {"level": DataNode}, - # FIXME Return type - None, None) + "GET_TEAM", + True, + False, + False, + ArgDesc(0, 0, DataNode), + {"level": DataNode}, + # Unsupported return type (TEAM_TYPE from ISO_FORTRAN_ENV). + lambda node: UnresolvedType(), + None, + ) HUGE = IAttr( - 'HUGE', True, False, True, - ArgDesc(1, 1, (Reference, Literal)), {}, - # FIXME Return type - None, None) + "HUGE", + True, + False, + True, + ArgDesc(1, 1, (Reference, Literal)), + {}, + _get_first_argument_type, + None, + ) HYPOT = IAttr( - 'HYPOT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, - # FIXME Return type - None, None) + "HYPOT", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + _get_first_argument_type, + None, + ) IACHAR = IAttr( - 'IACHAR', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, - # FIXME Return type - None, None) + "IACHAR", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) IALL = IAttr( - 'IALL', True, False, False, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, - # FIXME Return type - None, None) + "IALL", + True, + False, + False, + # FIXME Note to reviewer I think this should be + # ArgDesc(1, 2, (DataNode)), {"mask": DataNode} + # See https://gcc.gnu.org/onlinedocs/gfortran/IALL.html + # If this changes and "dim" is no longer a named argument, the + # return type function will not be correct. + ArgDesc(1, 1, (DataNode)), + {"dim": DataNode, "mask": DataNode}, + # There is no kind, but this call will work. + _get_integer_of_kind_with_optional_dim, + None, + ) IAND = IAttr( - 'IAND', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, - # FIXME Return type - None, None) + "IAND", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + lambda node: ( + node.arguments[0].datatype.copy() + if not isinstance(node.arguments[0], Literal) + else node.arguments[1].datatype.copy() + ), + None, + ) IANY = IAttr( - 'IANY', True, False, False, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, - # FIXME Return type - None, None) + "IANY", + True, + False, + False, + # FIXME Note to reviewer I think this should be + # ArgDesc(1, 2, (DataNode)), {"mask": DataNode} + # See https://gcc.gnu.org/onlinedocs/gfortran/IANY.html + # If this changes and "dim" is no longer a named argument, the + # return type function will not be correct. + ArgDesc(1, 1, (DataNode)), + {"dim": DataNode, "mask": DataNode}, + # There is no kind, but this call will work. + _get_integer_of_kind_with_optional_dim, + None, + ) IBCLR = IAttr( - 'IBCLR', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, - # FIXME Return type - None, None) + "IBCLR", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + _get_first_argument_type, + None, + ) IBITS = IAttr( - 'IBITS', True, True, False, - ArgDesc(3, 3, (DataNode)), {}, - # FIXME Return type - None, None) + "IBITS", + True, + True, + False, + ArgDesc(3, 3, (DataNode)), + {}, + _get_first_argument_type, + None, + ) IBSET = IAttr( - 'IBSET', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, - # FIXME Return type - None, None) + "IBSET", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + _get_first_argument_type, + None, + ) ICHAR = IAttr( - 'ICHAR', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, - # FIXME Return type - None, None) + "ICHAR", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) IEOR = IAttr( - 'IEOR', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, - # FIXME Return type - None, None) + "IEOR", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + lambda node: ( + node.arguments[0].datatype.copy() + if not isinstance(node.arguments[0], Literal) + else node.arguments[1].datatype.copy() + ), + None, + ) IMAGE_INDEX = IAttr( - 'IMAGE_INDEX', True, False, True, - ArgDesc(2, 3, (DataNode)), {}, - INTEGER_TYPE, None) + "IMAGE_INDEX", + True, + False, + True, + ArgDesc(2, 3, (DataNode)), + {}, + INTEGER_TYPE, + None, + ) IMAGE_STATUS = IAttr( - 'IMAGE_STATUS', True, False, False, - ArgDesc(1, 1, (DataNode)), {"team": DataNode}, - INTEGER_TYPE, None) + "IMAGE_STATUS", + True, + False, + False, + ArgDesc(1, 1, (DataNode)), + {"team": DataNode}, + INTEGER_TYPE, + None, + ) INDEX = IAttr( - 'INDEX', True, True, False, - ArgDesc(2, 2, (DataNode)), {"back": DataNode, "kind": DataNode}, - # FIXME Return type - None, None) + "INDEX", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {"back": DataNode, "kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) INT = IAttr( - 'INT', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, - # FIXME Return type - None, None) + "INT", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _int_return_type, + None, + ) IOR = IAttr( - 'IOR', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, - # FIXME Return type - None, None) + "IOR", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + lambda node: ScalarType( + ScalarType.Intrinsic.INTEGER, + ( + node.arguments[0].datatype.precision + if not isinstance(node.arguments[0], Literal) + else node.arguments[1].datatype.precision + ), + ), + None, + ) IPARITY = IAttr( - 'IPARITY', True, False, False, - ArgDesc(1, 2, (DataNode)), {"mask": DataNode}, - # FIXME Return type - None, None) + "IPARITY", + True, + False, + False, + ArgDesc(1, 2, (DataNode)), + {"mask": DataNode}, + _iparity_return_type, + None, + ) IS_CONTIGUOUS = IAttr( - 'IS_CONTIGUOUS', True, False, True, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "IS_CONTIGUOUS", + True, + False, + True, + ArgDesc(1, 1, (DataNode)), + {}, + BOOLEAN_TYPE, + None, + ) IS_IOSTAT_END = IAttr( - 'IS_IOSTAT_END', True, True, False, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "IS_IOSTAT_END", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {}, + BOOLEAN_TYPE, + None, + ) IS_IOSTAT_EOR = IAttr( - 'IS_IOSTAT_EOR', True, True, False, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "IS_IOSTAT_EOR", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {}, + BOOLEAN_TYPE, + None, + ) ISHFT = IAttr( - 'ISHFT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, - # FIXME Return type - None, None) + "ISHFT", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + _get_first_argument_type, + None, + ) ISHFTC = IAttr( - 'ISHFTC', True, True, False, - ArgDesc(2, 2, (DataNode)), {"size": DataNode}, - # FIXME Return type - None, None) + "ISHFTC", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {"size": DataNode}, + _get_first_argument_type, + None, + ) KIND = IAttr( - 'KIND', True, False, True, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "KIND", + True, + False, + True, + ArgDesc(1, 1, (DataNode)), + {}, + INTEGER_TYPE, + None, + ) LBOUND = IAttr( - 'LBOUND', True, False, True, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, - None, None) + "LBOUND", + True, + False, + True, + ArgDesc(1, 1, (DataNode)), + {"dim": DataNode, "kind": DataNode}, + _get_bound_function_return_type, + None, + ) LCOBOUND = IAttr( - 'LCOBOUND', True, False, True, - ArgDesc(1, 1, (DataNode)), {"dim": DataNode, "kind": DataNode}, - None, None) + "LCOBOUND", + True, + False, + True, + ArgDesc(1, 1, (DataNode)), + {"dim": DataNode, "kind": DataNode}, + _get_bound_function_return_type, + None, + ) LEADZ = IAttr( - 'LEADZ', True, True, False, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "LEADZ", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {}, + INTEGER_TYPE, + None, + ) LEN = IAttr( - 'LEN', True, False, True, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) + "LEN", + True, + False, + True, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) LEN_TRIM = IAttr( - 'LEN_TRIM', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) + "LEN_TRIM", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) LGE = IAttr( - 'LGE', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, None, None) + "LGE", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + BOOLEAN_TYPE, + None, + ) LGT = IAttr( - 'LGT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, None, None) + "LGT", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + BOOLEAN_TYPE, + None, + ) LLE = IAttr( - 'LLE', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, None, None) + "LLE", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + BOOLEAN_TYPE, + None, + ) LLT = IAttr( - 'LLT', True, True, False, - ArgDesc(2, 2, (DataNode)), {}, None, None) + "LLT", + True, + True, + False, + ArgDesc(2, 2, (DataNode)), + {}, + BOOLEAN_TYPE, + None, + ) LOG = IAttr( - 'LOG', True, True, False, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "LOG", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {}, + _get_first_argument_type, + None, + ) LOG_GAMMA = IAttr( - 'LOG_GAMMA', True, True, False, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "LOG_GAMMA", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {}, + _get_first_argument_type, + None, + ) LOG10 = IAttr( - 'LOG10', True, True, False, - ArgDesc(1, 1, (DataNode)), {}, None, None) + "LOG10", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {}, + _get_first_argument_type, + None, + ) LOGICAL = IAttr( - 'LOGICAL', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) + "LOGICAL", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _get_first_argument_type_with_optional_kind, + None, + ) MASKL = IAttr( - 'MASKL', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) + "MASKL", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) MASKR = IAttr( - 'MASKR', True, True, False, - ArgDesc(1, 1, (DataNode)), {"kind": DataNode}, None, None) + "MASKR", + True, + True, + False, + ArgDesc(1, 1, (DataNode)), + {"kind": DataNode}, + _get_integer_with_optional_kind, + None, + ) MATMUL = IAttr( - 'MATMUL', True, False, False, - ArgDesc(2, 2, DataNode), {}, None, None) + "MATMUL", + True, + False, + False, + ArgDesc(2, 2, DataNode), + {}, + # FIXME Implement MATMUL - Andy had? + NotImplementedError, + None, + ) MAX = IAttr( - 'MAX', True, True, False, - ArgDesc(2, None, DataNode), {}, None, None) + "MAX", + True, + True, + False, + ArgDesc(2, None, DataNode), + {}, + _get_first_argument_type, + None, + ) MAXEXPONENT = IAttr( - 'MAXEXPONENT', True, False, True, - ArgDesc(1, 1, DataNode), {}, None, None) + "MAXEXPONENT", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + INTEGER_TYPE, + None, + ) MAXLOC = IAttr( - 'MAXLOC', True, False, False, + "MAXLOC", + True, + False, + False, ArgDesc(1, 2, DataNode), - {"dim": DataNode, "mask": DataNode, "kind": DataNode, - "back": DataNode}, None, None) + { + "dim": DataNode, + "mask": DataNode, + "kind": DataNode, + "back": DataNode, + }, + _get_first_argument_intrinsic_with_optional_kind_and_dim, + None, + ) MAXVAL = IAttr( - 'MAXVAL', True, False, False, + "MAXVAL", + True, + False, + False, ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}, None, None) + {"dim": DataNode, "mask": DataNode}, + None, + None, + ) MERGE = IAttr( - 'MERGE', True, True, False, - ArgDesc(3, 3, DataNode), {}, None, None) + "MERGE", True, True, False, ArgDesc(3, 3, DataNode), {}, None, None + ) MERGE_BITS = IAttr( - 'MERGE_BITS', True, True, False, - ArgDesc(3, 3, DataNode), {}, None, None) + "MERGE_BITS", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {}, + None, + None, + ) MIN = IAttr( - 'MIN', True, True, False, - ArgDesc(2, None, DataNode), {}, None, None) + "MIN", + True, + True, + False, + ArgDesc(2, None, DataNode), + {}, + None, + None, + ) MINEXPONENT = IAttr( - 'MINEXPONENT', True, False, True, - ArgDesc(1, 1, DataNode), {}, None, None) + "MINEXPONENT", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) MINLOC = IAttr( - 'MINLOC', True, False, False, + "MINLOC", + True, + False, + False, ArgDesc(1, 2, DataNode), - {"dim": DataNode, "mask": DataNode, "kind": DataNode, - "back": DataNode}, None, None) + { + "dim": DataNode, + "mask": DataNode, + "kind": DataNode, + "back": DataNode, + }, + None, + None, + ) MINVAL = IAttr( - 'MINVAL', True, False, False, + "MINVAL", + True, + False, + False, ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}, None, None) + {"dim": DataNode, "mask": DataNode}, + None, + None, + ) MOD = IAttr( - 'MOD', True, True, False, - ArgDesc(2, 2, DataNode), {}, None, None) + "MOD", True, True, False, ArgDesc(2, 2, DataNode), {}, None, None + ) MODULO = IAttr( - 'MODULO', True, True, False, - ArgDesc(2, 2, DataNode), {}, None, None) + "MODULO", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + None, + None, + ) MOVE_ALLOC = IAttr( - 'MOVE_ALLOC', False, False, False, - ArgDesc(2, 2, DataNode), {"stat": DataNode, "errmsg": DataNode}, - None, None) + "MOVE_ALLOC", + False, + False, + False, + ArgDesc(2, 2, DataNode), + {"stat": DataNode, "errmsg": DataNode}, + None, + None, + ) MVBITS = IAttr( - 'MVBITS', True, True, False, - ArgDesc(5, 5, DataNode), {}, None, None) + "MVBITS", + True, + True, + False, + ArgDesc(5, 5, DataNode), + {}, + None, + None, + ) NEAREST = IAttr( - 'NEAREST', True, True, False, - ArgDesc(2, 2, DataNode), {}, None, None) + "NEAREST", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + None, + None, + ) NEW_LINE = IAttr( - 'NEW_LINE', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "NEW_LINE", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) NINT = IAttr( - 'NINT', True, True, False, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, None, None) + "NINT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, + None, + None, + ) NORM2 = IAttr( - 'NORM2', True, False, False, - ArgDesc(1, 2, DataNode), {}, None, None) + "NORM2", + True, + False, + False, + ArgDesc(1, 2, DataNode), + {}, + None, + None, + ) NOT = IAttr( - 'NOT', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "NOT", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + ) NULL = IAttr( - 'NULL', True, False, False, - ArgDesc(0, 0, DataNode), {"mold": DataNode}, None, None) + "NULL", + True, + False, + False, + ArgDesc(0, 0, DataNode), + {"mold": DataNode}, + None, + None, + ) NUM_IMAGES = IAttr( - 'NUM_IMAGES', True, False, False, - ArgDesc(0, 1, DataNode), {}, None, None) + "NUM_IMAGES", + True, + False, + False, + ArgDesc(0, 1, DataNode), + {}, + None, + None, + ) OUT_OF_RANGE = IAttr( - 'OUT_OF_RANGE', True, True, False, - ArgDesc(2, 2, DataNode), {"round": DataNode}, None, None) + "OUT_OF_RANGE", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"round": DataNode}, + None, + None, + ) PACK = IAttr( - 'PACK', True, False, False, - ArgDesc(2, 2, DataNode), {"vector": DataNode}, None, None) + "PACK", + True, + False, + False, + ArgDesc(2, 2, DataNode), + {"vector": DataNode}, + None, + None, + ) PARITY = IAttr( - 'PARITY', True, False, False, - ArgDesc(1, 2, DataNode), {}, None, None) + "PARITY", + True, + False, + False, + ArgDesc(1, 2, DataNode), + {}, + None, + None, + ) POPCNT = IAttr( - 'POPCNT', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "POPCNT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) POPPAR = IAttr( - 'POPPAR', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "POPPAR", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) PRECISION = IAttr( - 'PRECISION', True, False, True, - ArgDesc(1, 1, DataNode), {}, None, None) + "PRECISION", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) PRESENT = IAttr( - 'PRESENT', True, False, True, - ArgDesc(1, 1, DataNode), {}, None, None) + "PRESENT", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) PRODUCT = IAttr( - 'PRODUCT', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, - None, None) + "PRODUCT", + True, + False, + False, + ArgDesc(1, 1, DataNode), + {"dim": DataNode, "mask": DataNode}, + None, + None, + ) RADIX = IAttr( - 'RADIX', True, False, True, - ArgDesc(1, 1, DataNode), {}, None, None) + "RADIX", True, False, True, ArgDesc(1, 1, DataNode), {}, None, None + ) RANDOM_INIT = IAttr( - 'RANDOM_INIT', False, False, False, - ArgDesc(2, 2, DataNode), {}, None, None) + "RANDOM_INIT", + False, + False, + False, + ArgDesc(2, 2, DataNode), + {}, + None, + None, + ) RANDOM_NUMBER = IAttr( - 'RANDOM_NUMBER', False, False, False, - ArgDesc(1, 1, Reference), {}, None, None) + "RANDOM_NUMBER", + False, + False, + False, + ArgDesc(1, 1, Reference), + {}, + None, + None, + ) RANDOM_SEED = IAttr( - 'RANDOM_SEED', False, False, False, + "RANDOM_SEED", + False, + False, + False, ArgDesc(0, 0, Reference), - {"size": DataNode, "put": DataNode, "Get": DataNode}, None, None) + {"size": DataNode, "put": DataNode, "Get": DataNode}, + None, + None, + ) RANGE = IAttr( - 'RANGE', True, False, True, - ArgDesc(1, 1, Reference), {}, None, None) + "RANGE", + True, + False, + True, + ArgDesc(1, 1, Reference), + {}, + None, + None, + ) RANK = IAttr( - 'RANK', True, False, True, - ArgDesc(1, 1, Reference), {}, None, None) + "RANK", True, False, True, ArgDesc(1, 1, Reference), {}, None, None + ) REAL = IAttr( - 'REAL', True, True, False, - ArgDesc(1, 1, Reference), {"kind": DataNode}, None, None) + "REAL", + True, + True, + False, + ArgDesc(1, 1, Reference), + {"kind": DataNode}, + None, + None, + ) REDUCE = IAttr( - 'REDUCE', True, False, False, + "REDUCE", + True, + False, + False, ArgDesc(2, 3, Reference), {"mask": DataNode, "identity": DataNode, "ordered": DataNode}, - None, None) + None, + None, + ) REPEAT = IAttr( - 'REPEAT', True, False, False, - ArgDesc(2, 2, Reference), {}, None, None) + "REPEAT", + True, + False, + False, + ArgDesc(2, 2, Reference), + {}, + None, + None, + ) RESHAPE = IAttr( - 'RESHAPE', True, False, False, - ArgDesc(2, 2, Reference), {"pad": DataNode, "order": DataNode}, - None, None) + "RESHAPE", + True, + False, + False, + ArgDesc(2, 2, Reference), + {"pad": DataNode, "order": DataNode}, + None, + None, + ) RRSPACING = IAttr( - 'RRSPACING', True, True, False, - ArgDesc(1, 1, Reference), {}, None, None) + "RRSPACING", + True, + True, + False, + ArgDesc(1, 1, Reference), + {}, + None, + None, + ) SAME_TYPE_AS = IAttr( - 'SAME_TYPE_AS', True, False, True, - ArgDesc(2, 2, Reference), {}, None, None) + "SAME_TYPE_AS", + True, + False, + True, + ArgDesc(2, 2, Reference), + {}, + None, + None, + ) SCALE = IAttr( - 'SCALE', True, True, False, - ArgDesc(2, 2, Reference), {}, None, None) + "SCALE", + True, + True, + False, + ArgDesc(2, 2, Reference), + {}, + None, + None, + ) SCAN = IAttr( - 'SCAN', True, True, False, - ArgDesc(2, 2, Reference), {"back": DataNode, "kind": DataNode}, - None, None) + "SCAN", + True, + True, + False, + ArgDesc(2, 2, Reference), + {"back": DataNode, "kind": DataNode}, + None, + None, + ) SELECTED_CHAR_KIND = IAttr( - 'SELECTED_CHAR_KIND', True, False, False, - ArgDesc(1, 1, Reference), {}, None, None) + "SELECTED_CHAR_KIND", + True, + False, + False, + ArgDesc(1, 1, Reference), + {}, + None, + None, + ) SELECTED_INT_KIND = IAttr( - 'SELECTED_INT_KIND', True, False, False, - ArgDesc(1, 1, Reference), {}, None, None) + "SELECTED_INT_KIND", + True, + False, + False, + ArgDesc(1, 1, Reference), + {}, + None, + None, + ) SELECTED_REAL_KIND = IAttr( - 'SELECTED_REAL_KIND', True, False, False, + "SELECTED_REAL_KIND", + True, + False, + False, ArgDesc(0, 0, Reference), - {"P": DataNode, "R": DataNode, "radix": DataNode}, None, None) + {"P": DataNode, "R": DataNode, "radix": DataNode}, + None, + None, + ) SET_EXPONENT = IAttr( - 'SET_EXPONENT', True, True, False, - ArgDesc(2, 2, Reference), {}, None, None) + "SET_EXPONENT", + True, + True, + False, + ArgDesc(2, 2, Reference), + {}, + None, + None, + ) SHAPE = IAttr( - 'SHAPE', True, False, True, - ArgDesc(1, 1, Reference), {"kind": DataNode}, None, None) + "SHAPE", + True, + False, + True, + ArgDesc(1, 1, Reference), + {"kind": DataNode}, + None, + None, + ) SHIFTA = IAttr( - 'SHIFTA', True, True, False, - ArgDesc(2, 2, Reference), {}, None, None) + "SHIFTA", + True, + True, + False, + ArgDesc(2, 2, Reference), + {}, + None, + None, + ) SHIFTL = IAttr( - 'SHIFTL', True, True, False, - ArgDesc(2, 2, Reference), {}, None, None) + "SHIFTL", + True, + True, + False, + ArgDesc(2, 2, Reference), + {}, + None, + None, + ) SHIFTR = IAttr( - 'SHIFTR', True, True, False, - ArgDesc(2, 2, Reference), {}, None, None) + "SHIFTR", + True, + True, + False, + ArgDesc(2, 2, Reference), + {}, + None, + None, + ) SIGN = IAttr( - 'SIGN', True, True, False, - ArgDesc(2, 2, DataNode), {}, None, None) + "SIGN", True, True, False, ArgDesc(2, 2, DataNode), {}, None, None + ) SIN = IAttr( - 'SIN', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "SIN", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + ) SINH = IAttr( - 'SINH', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "SINH", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + ) SIZE = IAttr( - 'SIZE', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, - None, None) + "SIZE", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {"dim": DataNode, "kind": DataNode}, + None, + None, + ) SPACING = IAttr( - 'SPACING', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "SPACING", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) SPREAD = IAttr( - 'SPREAD', True, False, False, - ArgDesc(3, 3, DataNode), {}, None, None) + "SPREAD", + True, + False, + False, + ArgDesc(3, 3, DataNode), + {}, + None, + None, + ) SQRT = IAttr( - 'SQRT', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "SQRT", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + ) STOPPED_IMAGES = IAttr( - 'STOPPED_IMAGES', False, False, False, - ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}, - None, None) + "STOPPED_IMAGES", + False, + False, + False, + ArgDesc(0, 0, DataNode), + {"team": DataNode, "kind": DataNode}, + None, + None, + ) STORAGE_SIZE = IAttr( - 'STORAGE_SIZE', True, False, True, - ArgDesc(1, 1, DataNode), {"kind": DataNode}, None, None) + "STORAGE_SIZE", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {"kind": DataNode}, + None, + None, + ) SUM = IAttr( - 'SUM', True, False, False, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, - None, None) + "SUM", + True, + False, + False, + ArgDesc(1, 1, DataNode), + {"dim": DataNode, "mask": DataNode}, + None, + None, + ) SYSTEM_CLOCK = IAttr( - 'SYSTEM_CLOCK', False, False, False, + "SYSTEM_CLOCK", + False, + False, + False, ArgDesc(0, 0, DataNode), {"count": DataNode, "count_rate": DataNode, "count_max": DataNode}, - None, None) + None, + None, + ) TAN = IAttr( - 'TAN', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "TAN", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + ) TANH = IAttr( - 'TANH', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "TANH", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + ) TEAM_IMAGE = IAttr( - 'TEAM_IMAGE', True, False, False, - ArgDesc(0, 0, DataNode), {"team": DataNode}, None, None) + "TEAM_IMAGE", + True, + False, + False, + ArgDesc(0, 0, DataNode), + {"team": DataNode}, + None, + None, + ) THIS_IMAGE = IAttr( - 'THIS_IMAGE', True, False, False, + "THIS_IMAGE", + True, + False, + False, ArgDesc(0, 0, DataNode), {"coarray": DataNode, "team": DataNode, "dim": DataNode}, - None, None) + None, + None, + ) TINY = IAttr( - 'TINY', True, False, True, - ArgDesc(1, 1, (Reference, Literal)), {}, None, None) + "TINY", + True, + False, + True, + ArgDesc(1, 1, (Reference, Literal)), + {}, + None, + None, + ) TRAILZ = IAttr( - 'TRAILZ', True, True, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "TRAILZ", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) TRANSFER = IAttr( - 'TRANSFER', True, False, False, - ArgDesc(2, 2, DataNode), {"size": DataNode}, None, None) + "TRANSFER", + True, + False, + False, + ArgDesc(2, 2, DataNode), + {"size": DataNode}, + None, + None, + ) TRANSPOSE = IAttr( - 'TRANSPOSE', True, False, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "TRANSPOSE", + True, + False, + False, + ArgDesc(1, 1, DataNode), + {}, + None, + None, + ) TRIM = IAttr( - 'TRIM', True, False, False, - ArgDesc(1, 1, DataNode), {}, None, None) + "TRIM", True, False, False, ArgDesc(1, 1, DataNode), {}, None, None + ) UBOUND = IAttr( - 'UBOUND', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, - None, None) + "UBOUND", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {"dim": DataNode, "kind": DataNode}, + None, + None, + ) UCOBOUND = IAttr( - 'UCOBOUND', True, False, True, - ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, - None, None) + "UCOBOUND", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {"dim": DataNode, "kind": DataNode}, + None, + None, + ) UNPACK = IAttr( - 'UNPACK', True, False, False, - ArgDesc(3, 3, DataNode), {}, None, None) + "UNPACK", + True, + False, + False, + ArgDesc(3, 3, DataNode), + {}, + None, + None, + ) VERIFY = IAttr( - 'VERIFY', True, True, False, - ArgDesc(2, 2, DataNode), {"back": DataNode, "kind": DataNode}, - None, None) + "VERIFY", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {"back": DataNode, "kind": DataNode}, + None, + None, + ) def __hash__(self): return hash(self.name) @@ -1013,30 +2521,35 @@ def __init__(self, intrinsic, **kwargs): raise TypeError( f"IntrinsicCall 'intrinsic' argument should be an " f"instance of IntrinsicCall.Intrinsic, but found " - f"'{type(intrinsic).__name__}'.") + f"'{type(intrinsic).__name__}'." + ) # A Call expects a Reference to a Symbol, so give it a Reference # to an Intrinsicsymbol of the given intrinsic. super().__init__(**kwargs) - self.addchild(Reference(IntrinsicSymbol( - intrinsic.name, - intrinsic, - is_elemental=intrinsic.is_elemental, - is_pure=intrinsic.is_pure - ))) + self.addchild( + Reference( + IntrinsicSymbol( + intrinsic.name, + intrinsic, + is_elemental=intrinsic.is_elemental, + is_pure=intrinsic.is_pure, + ) + ) + ) @property def intrinsic(self): - ''' Return the type of intrinsic. + """Return the type of intrinsic. :returns: enumerated type capturing the type of intrinsic. :rtype: :py:class:`psyclone.psyir.nodes.IntrinsicCall.Intrinsic` - ''' + """ return self.routine.symbol.intrinsic def is_available_on_device(self, device_string: str = "") -> bool: - ''' + """ :param device_string: optional string to identify the offloading device (or its compiler-platform family). :returns: whether this intrinsic is available on an accelerated device. @@ -1044,7 +2557,7 @@ def is_available_on_device(self, device_string: str = "") -> bool: :raises ValueError: if the provided 'device_string' is not one of the supported values. - ''' + """ # Reduction operations that have more than a single argument sometimes # fail, so we avoid putting them on the accelerator device if self.intrinsic in REDUCTION_INTRINSICS: @@ -1060,11 +2573,12 @@ def is_available_on_device(self, device_string: str = "") -> bool: raise ValueError( f"Unsupported device_string value '{device_string}', the supported" - " values are '' (default), 'nvfortran-all', 'nvfortran-uniform'") + " values are '' (default), 'nvfortran-all', 'nvfortran-uniform'" + ) @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. @@ -1085,13 +2599,14 @@ 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 @@ -1102,7 +2617,8 @@ 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 # TODO #2302: For now we disable the positional arguments @@ -1124,7 +2640,8 @@ def create(cls, intrinsic, arguments=()): f"The optional argument '{name}' to intrinsic " f"'{intrinsic.name}' must be of type " f"'{intrinsic.optional_args[name].__name__}' but " - f"got '{type(arg[1]).__name__}'") + f"got '{type(arg[1]).__name__}'" + ) else: # If it not in the optional_args list it must be positional pos_arg_count += 1 @@ -1132,23 +2649,30 @@ 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 " f"positional arguments be of type " f"'{intrinsic.required_args.types}' " - f"but got a '{type(arg).__name__}'") + f"but got a '{type(arg).__name__}'" + ) pos_arg_count += 1 - if ((intrinsic.required_args.max_count is not None and - pos_arg_count > intrinsic.required_args.max_count) - or pos_arg_count < intrinsic.required_args.min_count): + if ( + intrinsic.required_args.max_count is not None + and pos_arg_count > intrinsic.required_args.max_count + ) or pos_arg_count < intrinsic.required_args.min_count: msg = f"The '{intrinsic.name}' intrinsic requires " - if (intrinsic.required_args.max_count is not None and - intrinsic.required_args.max_count > 0): - msg += (f"between {intrinsic.required_args.min_count} and " - f"{intrinsic.required_args.max_count} ") + if ( + intrinsic.required_args.max_count is not None + and intrinsic.required_args.max_count > 0 + ): + msg += ( + f"between {intrinsic.required_args.min_count} and " + f"{intrinsic.required_args.max_count} " + ) else: msg += f"at least {intrinsic.required_args.min_count} " msg += f"arguments but got {len(arguments)}." @@ -1164,16 +2688,17 @@ def create(cls, intrinsic, arguments=()): return call def reference_accesses(self) -> VariablesAccessMap: - ''' + """ :returns: a map of all the symbol accessed inside this node, the keys are Signatures (unique identifiers to a symbol and its structure acccessors) and the values are AccessSequence (a sequence of AccessTypes). - ''' + """ var_accesses = VariablesAccessMap() - if self.intrinsic.is_inquiry and isinstance(self.arguments[0], - Reference): + 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. @@ -1193,59 +2718,78 @@ def reference_accesses(self) -> VariablesAccessMap: # is a symbol, as they would act as the super() implementation. @property def is_elemental(self): - ''' + """ :returns: whether the routine being called is elemental (provided with an input array it will apply the operation individually to each of the array elements and return an array with the results). If this information is not known then it returns None. :rtype: NoneType | bool - ''' + """ return self.intrinsic.is_elemental @property def is_pure(self): - ''' + """ :returns: whether the routine being called is pure (guaranteed to return the same result when provided with the same argument values). If this information is not known then it returns None. :rtype: NoneType | bool - ''' + """ return self.intrinsic.is_pure @property def is_inquiry(self): - ''' + """ :returns: whether the routine being called is a query function (i.e. returns information about its argument rather than accessing any data referenced by the argument). If this information is not known then it returns None. :rtype: NoneType | bool - ''' + """ return self.intrinsic.is_inquiry # Intrinsics available on nvidia gpus with uniform (CPU and GPU) results when # compiled with the nvfortran "-gpu=uniform_math" flag NVFORTRAN_UNIFORM = ( - IntrinsicCall.Intrinsic.ABS, IntrinsicCall.Intrinsic.ACOS, - IntrinsicCall.Intrinsic.AINT, IntrinsicCall.Intrinsic.ANINT, - IntrinsicCall.Intrinsic.ASIN, IntrinsicCall.Intrinsic.ATAN, - IntrinsicCall.Intrinsic.ATAN2, IntrinsicCall.Intrinsic.COS, - IntrinsicCall.Intrinsic.COSH, IntrinsicCall.Intrinsic.DBLE, - IntrinsicCall.Intrinsic.DPROD, IntrinsicCall.Intrinsic.EXP, - IntrinsicCall.Intrinsic.IAND, IntrinsicCall.Intrinsic.IEOR, - IntrinsicCall.Intrinsic.INT, IntrinsicCall.Intrinsic.IOR, - IntrinsicCall.Intrinsic.LOG, IntrinsicCall.Intrinsic.NOT, - IntrinsicCall.Intrinsic.MAX, IntrinsicCall.Intrinsic.MIN, - IntrinsicCall.Intrinsic.MOD, IntrinsicCall.Intrinsic.NINT, - IntrinsicCall.Intrinsic.SIGN, IntrinsicCall.Intrinsic.SIN, - IntrinsicCall.Intrinsic.SINH, IntrinsicCall.Intrinsic.SQRT, - IntrinsicCall.Intrinsic.TAN, IntrinsicCall.Intrinsic.TANH, - IntrinsicCall.Intrinsic.UBOUND, IntrinsicCall.Intrinsic.MERGE, - IntrinsicCall.Intrinsic.PRODUCT, IntrinsicCall.Intrinsic.SIZE, - IntrinsicCall.Intrinsic.SUM, IntrinsicCall.Intrinsic.LBOUND, - IntrinsicCall.Intrinsic.MAXVAL, IntrinsicCall.Intrinsic.MINVAL, - IntrinsicCall.Intrinsic.TINY, IntrinsicCall.Intrinsic.HUGE + IntrinsicCall.Intrinsic.ABS, + IntrinsicCall.Intrinsic.ACOS, + IntrinsicCall.Intrinsic.AINT, + IntrinsicCall.Intrinsic.ANINT, + IntrinsicCall.Intrinsic.ASIN, + IntrinsicCall.Intrinsic.ATAN, + IntrinsicCall.Intrinsic.ATAN2, + IntrinsicCall.Intrinsic.COS, + IntrinsicCall.Intrinsic.COSH, + IntrinsicCall.Intrinsic.DBLE, + IntrinsicCall.Intrinsic.DPROD, + IntrinsicCall.Intrinsic.EXP, + IntrinsicCall.Intrinsic.IAND, + IntrinsicCall.Intrinsic.IEOR, + IntrinsicCall.Intrinsic.INT, + IntrinsicCall.Intrinsic.IOR, + IntrinsicCall.Intrinsic.LOG, + IntrinsicCall.Intrinsic.NOT, + IntrinsicCall.Intrinsic.MAX, + IntrinsicCall.Intrinsic.MIN, + IntrinsicCall.Intrinsic.MOD, + IntrinsicCall.Intrinsic.NINT, + IntrinsicCall.Intrinsic.SIGN, + IntrinsicCall.Intrinsic.SIN, + IntrinsicCall.Intrinsic.SINH, + IntrinsicCall.Intrinsic.SQRT, + IntrinsicCall.Intrinsic.TAN, + IntrinsicCall.Intrinsic.TANH, + IntrinsicCall.Intrinsic.UBOUND, + IntrinsicCall.Intrinsic.MERGE, + IntrinsicCall.Intrinsic.PRODUCT, + IntrinsicCall.Intrinsic.SIZE, + IntrinsicCall.Intrinsic.SUM, + IntrinsicCall.Intrinsic.LBOUND, + IntrinsicCall.Intrinsic.MAXVAL, + IntrinsicCall.Intrinsic.MINVAL, + IntrinsicCall.Intrinsic.TINY, + IntrinsicCall.Intrinsic.HUGE, ) # MATMUL can fail at link time depending on the precision of # its arguments. @@ -1253,7 +2797,9 @@ def is_inquiry(self): # All nvfortran intrinsics available on GPUs NVFORTRAN_ALL = NVFORTRAN_UNIFORM + ( - IntrinsicCall.Intrinsic.LOG10, IntrinsicCall.Intrinsic.REAL) + IntrinsicCall.Intrinsic.LOG10, + IntrinsicCall.Intrinsic.REAL, +) # For now the default intrinsics availabe on GPU are the same as nvfortran-all DEFAULT_DEVICE_INTRINISCS = NVFORTRAN_ALL @@ -1262,5 +2808,7 @@ def is_inquiry(self): # type of a PSyIR expression. # Intrinsics that perform a reduction on an array. REDUCTION_INTRINSICS = [ - IntrinsicCall.Intrinsic.SUM, IntrinsicCall.Intrinsic.MINVAL, - IntrinsicCall.Intrinsic.MAXVAL] + IntrinsicCall.Intrinsic.SUM, + IntrinsicCall.Intrinsic.MINVAL, + IntrinsicCall.Intrinsic.MAXVAL, +] diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 2cea2ca76d..d2609a8d1a 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -35,41 +35,69 @@ # Modified: R. W. Ford and S. Siso, STFC Daresbury Lab # ----------------------------------------------------------------------------- -''' +""" This module contains pytest tests for the IntrinsicCall node. TODO #2341 - tests need to be added for all of the supported intrinsics. -''' +""" import pytest from psyclone.psyir.nodes import ( - ArrayReference, Literal, Reference, Schedule, Assignment) + ArrayReference, + Literal, + Reference, + Schedule, + Assignment, +) from psyclone.psyir.nodes.intrinsic_call import ( - IntrinsicCall, IAttr, _get_first_argument_type, - _get_first_argument_logical_kind_with_optional_dim) + IntrinsicCall, + IAttr, + _get_first_argument_type, + _get_first_argument_logical_kind_with_optional_dim, + _get_real_with_argone_kind, + _get_real_with_x_kind, + _get_integer_of_kind_with_optional_dim, + _findloc_return_type, + _get_integer_with_optional_kind, + _int_return_type, + _iparity_return_type, + _get_bound_function_return_type, + _get_first_argument_type_with_optional_kind, + _get_first_argument_intrinsic_with_optional_kind_and_dim, +) from psyclone.psyir.symbols import ( - ArrayType, DataSymbol, INTEGER_TYPE, IntrinsicSymbol, REAL_TYPE, - BOOLEAN_TYPE, CHARACTER_TYPE, ScalarType, UnresolvedType) + ArrayType, + DataSymbol, + INTEGER_TYPE, + IntrinsicSymbol, + REAL_TYPE, + BOOLEAN_TYPE, + CHARACTER_TYPE, + ScalarType, + UnresolvedType, +) def test_intrinsic_enum(): - '''Basic test for the IntrinsicCall.Intrinsic enum.''' + """Basic test for the IntrinsicCall.Intrinsic enum.""" assert isinstance(IntrinsicCall.Intrinsic.MINVAL, IAttr) assert hash(IntrinsicCall.Intrinsic.MINVAL) == hash("MINVAL") def test_intrinsiccall_constructor(): - '''Tests that the class' constructor and its parent are called + """Tests that the class' constructor and its parent are called correctly. - ''' + """ # Wrong type of routine argument. with pytest.raises(TypeError) as err: _ = IntrinsicCall(None) - assert ("IntrinsicCall 'intrinsic' argument should be an instance of " - "IntrinsicCall.Intrinsic, but found 'NoneType'." in str(err.value)) + assert ( + "IntrinsicCall 'intrinsic' argument should be an instance of " + "IntrinsicCall.Intrinsic, but found 'NoneType'." in str(err.value) + ) # Check that supplied intrinsic and optional parent node is stored # correctly. sched = Schedule() @@ -81,26 +109,26 @@ def test_intrinsiccall_constructor(): def test_intrinsiccall_intrinsic(): - '''Tests the intrinsic property returns the type of intrinsics from + """Tests the intrinsic property returns the type of intrinsics from the intrinsic property. - ''' + """ call = IntrinsicCall(IntrinsicCall.Intrinsic.MAXVAL) assert call.intrinsic is IntrinsicCall.Intrinsic.MAXVAL def test_intrinsiccall_is_elemental(): - '''Tests the is_elemental() method works as expected. There are + """Tests the is_elemental() method works as expected. There are currently no elemental intrinsics so we can only test for False. - ''' + """ intrinsic = IntrinsicCall(IntrinsicCall.Intrinsic.SUM) assert intrinsic.is_elemental is False def test_intrinsiccall_is_pure(): - '''Tests that the is_pure() method works as expected.''' + """Tests that the is_pure() method works as expected.""" intrinsic = IntrinsicCall(IntrinsicCall.Intrinsic.SUM) assert intrinsic.is_pure is True intrinsic = IntrinsicCall(IntrinsicCall.Intrinsic.ALLOCATE) @@ -108,62 +136,66 @@ def test_intrinsiccall_is_pure(): def test_intrinsiccall_is_inquiry(): - '''Test that the is_inquiry() method works as expected.''' + """Test that the is_inquiry() method works as expected.""" intrinsic = IntrinsicCall(IntrinsicCall.Intrinsic.SUM) assert intrinsic.is_inquiry is False intrinsic = IntrinsicCall(IntrinsicCall.Intrinsic.ALLOCATED) assert intrinsic.is_inquiry is True -@pytest.mark.parametrize("intrinsic, result", [ - (IntrinsicCall.Intrinsic.ABS, True), - (IntrinsicCall.Intrinsic.MIN, True), - (IntrinsicCall.Intrinsic.MAX, True), - (IntrinsicCall.Intrinsic.MAXVAL, True), - (IntrinsicCall.Intrinsic.ALLOCATE, False), - (IntrinsicCall.Intrinsic.MATMUL, False), - (IntrinsicCall.Intrinsic.ACOS, True), - (IntrinsicCall.Intrinsic.AINT, True), - (IntrinsicCall.Intrinsic.ANINT, True), - (IntrinsicCall.Intrinsic.ASIN, True), - (IntrinsicCall.Intrinsic.ATAN, True), - (IntrinsicCall.Intrinsic.ATAN2, True), - (IntrinsicCall.Intrinsic.COS, True), - (IntrinsicCall.Intrinsic.COSH, True), - (IntrinsicCall.Intrinsic.DBLE, True), - (IntrinsicCall.Intrinsic.DPROD, True), - (IntrinsicCall.Intrinsic.EXP, True), - (IntrinsicCall.Intrinsic.IAND, True), - (IntrinsicCall.Intrinsic.IEOR, True), - (IntrinsicCall.Intrinsic.INT, True), - (IntrinsicCall.Intrinsic.IOR, True), - (IntrinsicCall.Intrinsic.LOG, True), - (IntrinsicCall.Intrinsic.LOG10, True), - (IntrinsicCall.Intrinsic.MOD, True), - (IntrinsicCall.Intrinsic.NINT, True), - (IntrinsicCall.Intrinsic.NOT, True), - (IntrinsicCall.Intrinsic.REAL, True), - (IntrinsicCall.Intrinsic.SIGN, True), - (IntrinsicCall.Intrinsic.SIN, True), - (IntrinsicCall.Intrinsic.SINH, True), - (IntrinsicCall.Intrinsic.SQRT, True), - (IntrinsicCall.Intrinsic.TAN, True), - (IntrinsicCall.Intrinsic.TANH, True), - (IntrinsicCall.Intrinsic.PRODUCT, True), - (IntrinsicCall.Intrinsic.SUM, True), - (IntrinsicCall.Intrinsic.LBOUND, True), - (IntrinsicCall.Intrinsic.UBOUND, True)]) +@pytest.mark.parametrize( + "intrinsic, result", + [ + (IntrinsicCall.Intrinsic.ABS, True), + (IntrinsicCall.Intrinsic.MIN, True), + (IntrinsicCall.Intrinsic.MAX, True), + (IntrinsicCall.Intrinsic.MAXVAL, True), + (IntrinsicCall.Intrinsic.ALLOCATE, False), + (IntrinsicCall.Intrinsic.MATMUL, False), + (IntrinsicCall.Intrinsic.ACOS, True), + (IntrinsicCall.Intrinsic.AINT, True), + (IntrinsicCall.Intrinsic.ANINT, True), + (IntrinsicCall.Intrinsic.ASIN, True), + (IntrinsicCall.Intrinsic.ATAN, True), + (IntrinsicCall.Intrinsic.ATAN2, True), + (IntrinsicCall.Intrinsic.COS, True), + (IntrinsicCall.Intrinsic.COSH, True), + (IntrinsicCall.Intrinsic.DBLE, True), + (IntrinsicCall.Intrinsic.DPROD, True), + (IntrinsicCall.Intrinsic.EXP, True), + (IntrinsicCall.Intrinsic.IAND, True), + (IntrinsicCall.Intrinsic.IEOR, True), + (IntrinsicCall.Intrinsic.INT, True), + (IntrinsicCall.Intrinsic.IOR, True), + (IntrinsicCall.Intrinsic.LOG, True), + (IntrinsicCall.Intrinsic.LOG10, True), + (IntrinsicCall.Intrinsic.MOD, True), + (IntrinsicCall.Intrinsic.NINT, True), + (IntrinsicCall.Intrinsic.NOT, True), + (IntrinsicCall.Intrinsic.REAL, True), + (IntrinsicCall.Intrinsic.SIGN, True), + (IntrinsicCall.Intrinsic.SIN, True), + (IntrinsicCall.Intrinsic.SINH, True), + (IntrinsicCall.Intrinsic.SQRT, True), + (IntrinsicCall.Intrinsic.TAN, True), + (IntrinsicCall.Intrinsic.TANH, True), + (IntrinsicCall.Intrinsic.PRODUCT, True), + (IntrinsicCall.Intrinsic.SUM, True), + (IntrinsicCall.Intrinsic.LBOUND, True), + (IntrinsicCall.Intrinsic.UBOUND, True), + ], +) def test_intrinsiccall_is_available_on_device(intrinsic, result): - '''Tests that the is_available_on_device() method works as expected.''' + """Tests that the is_available_on_device() method works as expected.""" intrinsic_call = IntrinsicCall(intrinsic) # For now default and nvfortran-all are the same assert intrinsic_call.is_available_on_device() is result - assert intrinsic_call.is_available_on_device('nvfortran-all') is result + assert intrinsic_call.is_available_on_device("nvfortran-all") is result def test_intrinsiccall_reductions_is_available_on_device(): - '''Tests that the is_available_on_device() refuses reduction intrinsics - with optional arguments''' + """Tests that the is_available_on_device() refuses reduction intrinsics + with optional arguments""" intrinsic_call = IntrinsicCall(IntrinsicCall.Intrinsic.SUM) intrinsic_call.addchild(Reference(DataSymbol("result", REAL_TYPE))) # This is avaliabe on the device @@ -175,9 +207,9 @@ def test_intrinsiccall_reductions_is_available_on_device(): def test_intrinsiccall_is_available_on_device_with_device_string(): - '''Tests that the is_available_on_device() method with a device_string + """Tests that the is_available_on_device() method with a device_string argument provides different results with the 'nvfortran-uniform' - ''' + """ intrinsic_call = IntrinsicCall(IntrinsicCall.Intrinsic.LOG10) assert not intrinsic_call.is_available_on_device("nvfortran-uniform") intrinsic_call = IntrinsicCall(IntrinsicCall.Intrinsic.REAL) @@ -185,50 +217,59 @@ def test_intrinsiccall_is_available_on_device_with_device_string(): with pytest.raises(ValueError) as err: assert not intrinsic_call.is_available_on_device("invalid") - assert ("Unsupported device_string value 'invalid', the supported values" - " are '' (default), 'nvfortran-all', 'nvfortran-uniform'" - in str(err.value)) + assert ( + "Unsupported device_string value 'invalid', the supported values" + " are '' (default), 'nvfortran-all', 'nvfortran-uniform'" + in str(err.value) + ) def test_intrinsiccall_alloc_create(): - '''Tests the create() method supports various forms of 'allocate'. - - ''' - sym = DataSymbol("my_array", ArrayType(INTEGER_TYPE, - [ArrayType.Extent.DEFERRED])) - bsym = DataSymbol("my_array2", ArrayType(INTEGER_TYPE, - [ArrayType.Extent.DEFERRED])) + """Tests the create() method supports various forms of 'allocate'.""" + sym = DataSymbol( + "my_array", ArrayType(INTEGER_TYPE, [ArrayType.Extent.DEFERRED]) + ) + bsym = DataSymbol( + "my_array2", ArrayType(INTEGER_TYPE, [ArrayType.Extent.DEFERRED]) + ) isym = DataSymbol("ierr", INTEGER_TYPE) csym = DataSymbol("msg", CHARACTER_TYPE) # Straightforward allocation of an array. alloc = IntrinsicCall.create( IntrinsicCall.Intrinsic.ALLOCATE, - [ArrayReference.create(sym, [Literal("20", INTEGER_TYPE)])]) + [ArrayReference.create(sym, [Literal("20", INTEGER_TYPE)])], + ) assert isinstance(alloc, IntrinsicCall) assert alloc.intrinsic is IntrinsicCall.Intrinsic.ALLOCATE assert isinstance(alloc.routine.symbol, IntrinsicSymbol) assert alloc.routine.name == "ALLOCATE" alloc = IntrinsicCall.create( IntrinsicCall.Intrinsic.ALLOCATE, - [Reference(sym), ("Mold", Reference(bsym))]) + [Reference(sym), ("Mold", Reference(bsym))], + ) assert isinstance(alloc, IntrinsicCall) assert alloc.argument_names == [None, "Mold"] alloc = IntrinsicCall.create( IntrinsicCall.Intrinsic.ALLOCATE, - [Reference(sym), ("Source", Reference(bsym)), - ("stat", Reference(isym)), ("errmsg", Reference(csym))]) + [ + Reference(sym), + ("Source", Reference(bsym)), + ("stat", Reference(isym)), + ("errmsg", Reference(csym)), + ], + ) assert alloc.argument_names == [None, "Source", "stat", "errmsg"] def test_intrinsiccall_dealloc_create(): - '''Tests for the creation of a 'deallocate' call. - - ''' - sym = DataSymbol("my_array", ArrayType(INTEGER_TYPE, - [ArrayType.Extent.DEFERRED])) + """Tests for the creation of a 'deallocate' call.""" + sym = DataSymbol( + "my_array", ArrayType(INTEGER_TYPE, [ArrayType.Extent.DEFERRED]) + ) ierr = DataSymbol("ierr", INTEGER_TYPE) dealloc = IntrinsicCall.create( - IntrinsicCall.Intrinsic.DEALLOCATE, [Reference(sym)]) + IntrinsicCall.Intrinsic.DEALLOCATE, [Reference(sym)] + ) assert isinstance(dealloc, IntrinsicCall) assert dealloc.intrinsic is IntrinsicCall.Intrinsic.DEALLOCATE assert isinstance(dealloc.routine.symbol, IntrinsicSymbol) @@ -236,19 +277,20 @@ def test_intrinsiccall_dealloc_create(): assert dealloc.arguments[0].symbol is sym # With 'stat' optional argument. dealloc = IntrinsicCall.create( - IntrinsicCall.Intrinsic.DEALLOCATE, [Reference(sym), - ("Stat", Reference(ierr))]) + IntrinsicCall.Intrinsic.DEALLOCATE, + [Reference(sym), ("Stat", Reference(ierr))], + ) assert dealloc.argument_names == [None, "Stat"] def test_intrinsiccall_random_create(): - '''Tests for the creation of a 'random' call. - - ''' - sym = DataSymbol("my_array", ArrayType(REAL_TYPE, - [ArrayType.Extent.DEFERRED])) + """Tests for the creation of a 'random' call.""" + sym = DataSymbol( + "my_array", ArrayType(REAL_TYPE, [ArrayType.Extent.DEFERRED]) + ) rand = IntrinsicCall.create( - IntrinsicCall.Intrinsic.RANDOM_NUMBER, [Reference(sym)]) + IntrinsicCall.Intrinsic.RANDOM_NUMBER, [Reference(sym)] + ) assert isinstance(rand, IntrinsicCall) assert rand.intrinsic is IntrinsicCall.Intrinsic.RANDOM_NUMBER assert isinstance(rand.routine.symbol, IntrinsicSymbol) @@ -256,22 +298,27 @@ def test_intrinsiccall_random_create(): assert rand.arguments[0].symbol is sym -@pytest.mark.parametrize("intrinsic_call", [ - IntrinsicCall.Intrinsic.MINVAL, IntrinsicCall.Intrinsic.MAXVAL, - IntrinsicCall.Intrinsic.SUM]) +@pytest.mark.parametrize( + "intrinsic_call", + [ + IntrinsicCall.Intrinsic.MINVAL, + IntrinsicCall.Intrinsic.MAXVAL, + IntrinsicCall.Intrinsic.SUM, + ], +) def test_intrinsiccall_minmaxsum_create(intrinsic_call): - '''Tests for the creation of the different argument options for + """Tests for the creation of the different argument options for 'minval', 'maxval' and 'sum' IntrinsicCalls. - ''' + """ array = DataSymbol( - "my_array", ArrayType(REAL_TYPE, [ArrayType.Extent.DEFERRED])) + "my_array", ArrayType(REAL_TYPE, [ArrayType.Extent.DEFERRED]) + ) dim = DataSymbol("dim", INTEGER_TYPE) mask = DataSymbol("mask", BOOLEAN_TYPE) # array only - intrinsic = IntrinsicCall.create( - intrinsic_call, [Reference(array)]) + intrinsic = IntrinsicCall.create(intrinsic_call, [Reference(array)]) assert isinstance(intrinsic, IntrinsicCall) assert intrinsic.intrinsic is intrinsic_call assert isinstance(intrinsic.routine.symbol, IntrinsicSymbol) @@ -280,47 +327,56 @@ def test_intrinsiccall_minmaxsum_create(intrinsic_call): assert intrinsic.arguments[0].symbol is array # array and optional dim intrinsic = IntrinsicCall.create( - intrinsic_call, [Reference(array), ("dim", Reference(dim))]) + intrinsic_call, [Reference(array), ("dim", Reference(dim))] + ) assert intrinsic.argument_names == [None, "dim"] # array and optional mask intrinsic = IntrinsicCall.create( - intrinsic_call, [Reference(array), ("mask", Reference(mask))]) + intrinsic_call, [Reference(array), ("mask", Reference(mask))] + ) assert intrinsic.argument_names == [None, "mask"] # array and optional dim then optional mask intrinsic = IntrinsicCall.create( - intrinsic_call, [Reference(array), ("dim", Reference(dim)), - ("mask", Reference(mask))]) + intrinsic_call, + [Reference(array), ("dim", Reference(dim)), ("mask", Reference(mask))], + ) assert intrinsic.argument_names == [None, "dim", "mask"] # array and optional mask then optional dim intrinsic = IntrinsicCall.create( - intrinsic_call, [Reference(array), ("mask", Reference(mask)), - ("dim", Reference(dim))]) + intrinsic_call, + [Reference(array), ("mask", Reference(mask)), ("dim", Reference(dim))], + ) assert intrinsic.argument_names == [None, "mask", "dim"] # array and optional literal mask and optional literal dim intrinsic = IntrinsicCall.create( - intrinsic_call, [ + intrinsic_call, + [ Reference(array), ("mask", Literal("1", INTEGER_TYPE)), - ("dim", Literal("false", BOOLEAN_TYPE))]) + ("dim", Literal("false", BOOLEAN_TYPE)), + ], + ) assert intrinsic.argument_names == [None, "mask", "dim"] -@pytest.mark.parametrize("intrinsic_call", [ - IntrinsicCall.Intrinsic.TINY, IntrinsicCall.Intrinsic.HUGE]) +@pytest.mark.parametrize( + "intrinsic_call", + [IntrinsicCall.Intrinsic.TINY, IntrinsicCall.Intrinsic.HUGE], +) @pytest.mark.parametrize("form", ["array", "literal"]) def test_intrinsiccall_tinyhuge_create(intrinsic_call, form): - '''Tests for the creation of the different argument options for + """Tests for the creation of the different argument options for 'tiny' and 'huge' IntrinsicCalls. - ''' + """ if form == "array": array = DataSymbol( - "my_array", ArrayType(REAL_TYPE, [ArrayType.Extent.DEFERRED])) + "my_array", ArrayType(REAL_TYPE, [ArrayType.Extent.DEFERRED]) + ) arg = Reference(array) else: # "literal" arg = Literal("1.0", REAL_TYPE) - intrinsic = IntrinsicCall.create( - intrinsic_call, [arg]) + intrinsic = IntrinsicCall.create(intrinsic_call, [arg]) assert isinstance(intrinsic, IntrinsicCall) assert intrinsic.intrinsic is intrinsic_call assert isinstance(intrinsic.routine.symbol, IntrinsicSymbol) @@ -333,45 +389,58 @@ def test_intrinsiccall_tinyhuge_create(intrinsic_call, form): def test_intrinsiccall_create_errors(): - '''Checks for the validation/type checking in the create() method. - - ''' - sym = DataSymbol("my_array", ArrayType(INTEGER_TYPE, - [ArrayType.Extent.DEFERRED])) + """Checks for the validation/type checking in the create() method.""" + sym = DataSymbol( + "my_array", ArrayType(INTEGER_TYPE, [ArrayType.Extent.DEFERRED]) + ) aref = ArrayReference.create(sym, [Literal("20", INTEGER_TYPE)]) with pytest.raises(TypeError) as err: IntrinsicCall.create("ALLOCATE", [Reference(sym)]) - assert ("'intrinsic' argument should be an instance of " - "IntrinsicCall.Intrinsic, but found 'str'" in str(err.value)) + assert ( + "'intrinsic' argument should be an instance of " + "IntrinsicCall.Intrinsic, but found 'str'" in str(err.value) + ) # Supplied arguments must be a list. with pytest.raises(TypeError) as err: IntrinsicCall.create(IntrinsicCall.Intrinsic.ALLOCATE, aref) - assert ("IntrinsicCall.create() 'arguments' argument should be an Iterable" - " but found 'ArrayReference'" in str(err.value)) + assert ( + "IntrinsicCall.create() 'arguments' argument should be an Iterable" + " but found 'ArrayReference'" in str(err.value) + ) # An allocate must have one or more References as argument. with pytest.raises(ValueError) as err: IntrinsicCall.create(IntrinsicCall.Intrinsic.ALLOCATE, []) - assert ("The 'ALLOCATE' intrinsic requires at least 1 arguments but " - "got 0" in str(err.value)) + assert ( + "The 'ALLOCATE' intrinsic requires at least 1 arguments but " + "got 0" in str(err.value) + ) # The random intrinsic only accepts one argument. with pytest.raises(ValueError) as err: - IntrinsicCall.create(IntrinsicCall.Intrinsic.RANDOM_NUMBER, - [aref, aref.copy()]) - assert ("The 'RANDOM_NUMBER' intrinsic requires between 1 and 1 arguments " - "but got 2" in str(err.value)) + IntrinsicCall.create( + IntrinsicCall.Intrinsic.RANDOM_NUMBER, [aref, aref.copy()] + ) + assert ( + "The 'RANDOM_NUMBER' intrinsic requires between 1 and 1 arguments " + "but got 2" in str(err.value) + ) # Wrong type for a positional argument. with pytest.raises(TypeError) as err: - IntrinsicCall.create(IntrinsicCall.Intrinsic.ALLOCATE, - [sym]) - assert ("The 'ALLOCATE' intrinsic requires that positional arguments be " - "of type " in str(err.value)) + IntrinsicCall.create(IntrinsicCall.Intrinsic.ALLOCATE, [sym]) + assert ( + "The 'ALLOCATE' intrinsic requires that positional arguments be " + "of type " in str(err.value) + ) assert "but got a 'DataSymbol'" in str(err.value) # Positional argument after named argument. with pytest.raises(ValueError) as err: - IntrinsicCall.create(IntrinsicCall.Intrinsic.DEALLOCATE, - [Reference(sym), ("stat", aref), aref]) - assert ("Found a positional argument *after* a named argument ('stat'). " - "This is invalid." in str(err.value)) + IntrinsicCall.create( + IntrinsicCall.Intrinsic.DEALLOCATE, + [Reference(sym), ("stat", aref), aref], + ) + assert ( + "Found a positional argument *after* a named argument ('stat'). " + "This is invalid." in str(err.value) + ) # TODO #2303: We can not enable the validation of positional parameters # unless we store their name, otherwise when we parse a positional argument @@ -393,52 +462,64 @@ def test_intrinsiccall_create_errors(): # Wrong type for the name of an optional argument. with pytest.raises(TypeError) as err: - IntrinsicCall.create(IntrinsicCall.Intrinsic.ALLOCATE, - [aref, (sym, sym)]) - assert ("Optional arguments to an IntrinsicCall must be specified by a " - "(str, Reference) tuple but got a DataSymbol instead of a str" - in str(err.value)) + IntrinsicCall.create( + IntrinsicCall.Intrinsic.ALLOCATE, [aref, (sym, sym)] + ) + assert ( + "Optional arguments to an IntrinsicCall must be specified by a " + "(str, Reference) tuple but got a DataSymbol instead of a str" + in str(err.value) + ) # Wrong type for an optional argument. with pytest.raises(TypeError) as err: - IntrinsicCall.create(IntrinsicCall.Intrinsic.ALLOCATE, - [aref, ("stat", sym)]) - assert ("The optional argument 'stat' to intrinsic 'ALLOCATE' must be " - "of type 'Reference' but got 'DataSymbol'" in str(err.value)) + IntrinsicCall.create( + IntrinsicCall.Intrinsic.ALLOCATE, [aref, ("stat", sym)] + ) + assert ( + "The optional argument 'stat' to intrinsic 'ALLOCATE' must be " + "of type 'Reference' but got 'DataSymbol'" in str(err.value) + ) def test_create_positional_arguments_with_names(): - ''' Test the create method when given named positional arguments.''' - sym = DataSymbol("my_array", - ArrayType(INTEGER_TYPE, [ArrayType.Extent.DEFERRED])) + """Test the create method when given named positional arguments.""" + sym = DataSymbol( + "my_array", ArrayType(INTEGER_TYPE, [ArrayType.Extent.DEFERRED]) + ) aref = ArrayReference.create(sym, [Literal("20", INTEGER_TYPE)]) bref = ArrayReference.create(sym, [Literal("20", INTEGER_TYPE)]) # All of these are valid - intr = IntrinsicCall.create(IntrinsicCall.Intrinsic.DOT_PRODUCT, - [aref.copy(), bref.copy()]) + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.DOT_PRODUCT, [aref.copy(), bref.copy()] + ) assert isinstance(intr, IntrinsicCall) assert intr.arguments[0] == aref assert intr.arguments[1] == bref assert intr.argument_names == [None, None] - intr = IntrinsicCall.create(IntrinsicCall.Intrinsic.DOT_PRODUCT, - [aref.copy(), ("vector_b", bref.copy())]) + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.DOT_PRODUCT, + [aref.copy(), ("vector_b", bref.copy())], + ) assert isinstance(intr, IntrinsicCall) assert intr.arguments[0] == aref assert intr.arguments[1] == bref assert intr.argument_names == [None, "vector_b"] - intr = IntrinsicCall.create(IntrinsicCall.Intrinsic.DOT_PRODUCT, - [("vector_a", aref.copy()), - ("vector_b", bref.copy())]) + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.DOT_PRODUCT, + [("vector_a", aref.copy()), ("vector_b", bref.copy())], + ) assert isinstance(intr, IntrinsicCall) assert intr.arguments[0] == aref assert intr.arguments[1] == bref assert intr.argument_names == ["vector_a", "vector_b"] - intr = IntrinsicCall.create(IntrinsicCall.Intrinsic.DOT_PRODUCT, - [("vector_b", bref.copy()), - ("vector_a", aref.copy())]) + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.DOT_PRODUCT, + [("vector_b", bref.copy()), ("vector_a", aref.copy())], + ) assert isinstance(intr, IntrinsicCall) assert intr.arguments[0] == bref assert intr.arguments[1] == aref @@ -447,22 +528,22 @@ def test_create_positional_arguments_with_names(): @pytest.mark.parametrize("operator", ["lbound", "ubound", "size"]) def test_reference_accesses_bounds(operator, fortran_reader): - '''Test that the reference_accesses method behaves as expected when + """Test that the reference_accesses method behaves as expected when the reference is the first argument to either the lbound or ubound intrinsic as that is simply looking up the array bounds (therefore the access is an enquiry) and when the reference is the second argument of either the lbound or ubound intrinsic (in which case the access should be a read). - ''' - code = f'''module test + """ + code = f"""module test contains subroutine tmp() real, dimension(:,:), allocatable:: a, b integer :: n n = {operator}(a, b(1,1)) end subroutine tmp - end module test''' + end module test""" psyir = fortran_reader.psyir_from_source(code) schedule = psyir.walk(Assignment)[0] @@ -473,19 +554,19 @@ def test_reference_accesses_bounds(operator, fortran_reader): def test_enumerator_name_matches_name_field(): - ''' + """ Test that the name given to every IntrinsicCall matches the corresponding name field in the IAttr namedtuple. - ''' + """ for intrinsic_entry in IntrinsicCall.Intrinsic: assert intrinsic_entry._name_ == intrinsic_entry.name def test_allocate_intrinsic(fortran_reader, fortran_writer): - ''' + """ Test the ALLOCATE 'intrinsic'. - ''' - code = ''' + """ + code = """ program test_prog implicit none integer :: ierr @@ -495,7 +576,7 @@ def test_allocate_intrinsic(fortran_reader, fortran_writer): allocate(arr2, mold=arr1) allocate(arr2, source=arr1, errmsg=msg) end program test_prog -''' +""" psyir = fortran_reader.psyir_from_source(code) assert len(psyir.walk(IntrinsicCall)) == 3 result = fortran_writer(psyir).lower() @@ -505,10 +586,10 @@ def test_allocate_intrinsic(fortran_reader, fortran_writer): def test_deallocate_intrinsic(fortran_reader, fortran_writer): - ''' + """ Test the DEALLOCATE 'intrinsic'. - ''' - code = ''' + """ + code = """ program test_prog implicit none integer :: ierr @@ -516,7 +597,7 @@ def test_deallocate_intrinsic(fortran_reader, fortran_writer): deallocate(arr1) deallocate(arr1, stat=ierr) end program test_prog -''' +""" psyir = fortran_reader.psyir_from_source(code) assert len(psyir.walk(IntrinsicCall)) == 2 result = fortran_writer(psyir).lower() @@ -525,10 +606,10 @@ def test_deallocate_intrinsic(fortran_reader, fortran_writer): def test_index_intrinsic(fortran_reader, fortran_writer): - ''' + """ Test the INDEX intrinsic. - ''' - code = ''' + """ + code = """ program test_prog implicit none character(len=10) :: clname @@ -539,7 +620,7 @@ def test_index_intrinsic(fortran_reader, fortran_writer): ind2 = INDEX( clname, '.', kind=4) - 1 end program test_prog -''' +""" psyir = fortran_reader.psyir_from_source(code) assert len(psyir.walk(IntrinsicCall)) == 3 result = fortran_writer(psyir).lower() @@ -549,10 +630,10 @@ def test_index_intrinsic(fortran_reader, fortran_writer): def test_verify_intrinsic(fortran_reader, fortran_writer): - ''' + """ Test the VERIFY intrinsic. - ''' - code = ''' + """ + code = """ program test_prog implicit none character(len=10) :: clname @@ -569,22 +650,28 @@ def test_verify_intrinsic(fortran_reader, fortran_writer): == 0 ) idom = jpdom_local end program test_prog -''' +""" psyir = fortran_reader.psyir_from_source(code) # Should have 4 VERIFY and 2 KIND assert len(psyir.walk(IntrinsicCall)) == 6 result = fortran_writer(psyir).lower() assert "if (verify(clname(ind1:ind2), '0123456789') == 0) then" in result - assert ("if (verify(clname(ind1:ind2), '0123456789', back=.true.) " - "== 0) then" in result) - assert ("if (verify(clname(ind1:ind2), '0123456789', kind=kind(1)) " - "== 0) then" in result) - assert ("if (verify(clname(ind1:ind2), '0123456789', kind=kind(1), " - "back=.true.) == 0) then" in result) + assert ( + "if (verify(clname(ind1:ind2), '0123456789', back=.true.) " + "== 0) then" in result + ) + assert ( + "if (verify(clname(ind1:ind2), '0123456789', kind=kind(1)) " + "== 0) then" in result + ) + assert ( + "if (verify(clname(ind1:ind2), '0123456789', kind=kind(1), " + "back=.true.) == 0) then" in result + ) def test_get_first_argument_type(fortran_reader): - '''Test the _get_first_argument_type helper function.''' + """Test the _get_first_argument_type helper function.""" code = """subroutine x integer :: a, b a = 1 @@ -598,8 +685,8 @@ def test_get_first_argument_type(fortran_reader): def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): - '''Test the _get_first_argument_logical_kind_with_optional_dim helper - function.''' + """Test the _get_first_argument_logical_kind_with_optional_dim helper + function.""" code = """subroutine x logical, dimension(100,100) :: a logical, dimension(100) :: b @@ -621,38 +708,509 @@ def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): assert dtype.datatype.precision == ScalarType.Precision.UNDEFINED -@pytest.mark.parametrize("code, expected", [ - ("""subroutine x +def test_get_real_with_argone_kind(fortran_reader): + """Test the _get_real_with_argone_kind helper function.""" + code = """subroutine y + real*8 :: x + x = BESSEL_J0(x) + end subroutine y""" + psyir = fortran_reader.psyir_from_source(code) + bessel_call = psyir.walk(ArrayReference)[0] + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.BESSEL_J0, [bessel_call.indices[0].copy()] + ) + dtype = _get_real_with_argone_kind(intr) + assert dtype.intrinsic == ScalarType.Intrinsic.REAL + assert dtype.precision == 8 + + +def test_get_real_with_x_kind(fortran_reader): + """Test the _get_real_with_x_kind helper function.""" + code = """subroutine y + real*8 :: x + x = BESSEL_JN(1, 2, x) + x = BESSEL_JN(1, x) + end subroutine y""" + psyir = fortran_reader.psyir_from_source(code) + bessel_calls = psyir.walk(ArrayReference) + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.BESSEL_JN, + [x.copy() for x in bessel_calls[0].indices], + ) + dtype = _get_real_with_x_kind(intr) + assert dtype.intrinsic == ScalarType.Intrinsic.REAL + assert dtype.precision == 8 + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.BESSEL_JN, + [x.copy() for x in bessel_calls[1].indices], + ) + dtype = _get_real_with_x_kind(intr) + assert dtype.intrinsic == ScalarType.Intrinsic.REAL + assert dtype.precision == 8 + + +def test_get_integer_of_kind_with_optional_dim(fortran_reader): + """Test the _get_integer_of_kind_with_optional_dim helper function.""" + code = """ + subroutine y + logical, dimension(100,100) :: a + integer :: b + integer*8, dimension(100) :: c + + b = COUNT(a) + c = COUNT(a, dim=1, kind=8) + end subroutine y""" + psyir = fortran_reader.psyir_from_source(code) + intrs = psyir.walk(IntrinsicCall) + + res = _get_integer_of_kind_with_optional_dim(intrs[0]) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == ScalarType.Precision.UNDEFINED + + res = _get_integer_of_kind_with_optional_dim(intrs[1]) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision.value == "8" + assert len(res.shape) == 1 + assert res.shape[0] == ArrayType.Extent.DEFERRED + + +def test_findloc_return_type(fortran_reader): + """Test the _findloc_return_type helper function.""" + code = """ + subroutine y + integer, dimension(100) :: a + integer, dimension(1) :: b + b = FINDLOC(a, 1) + end subroutine y""" + psyir = fortran_reader.psyir_from_source(code) + intrs = psyir.walk(ArrayReference) + intr = IntrinsicCall.create( + IntrinsicCall.Intrinsic.FINDLOC, [x.copy() for x in intrs[0].indices] + ) + res = _findloc_return_type(intr) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == ScalarType.Precision.UNDEFINED + assert len(res.shape) == 1 + assert res.shape[0].upper.value == "1" + assert res.shape[0].lower.value == "1" + + # TODO #2823 adding namedargs makes this a CodeBlock so can't test yet. + + +def test_get_integer_with_optional_kind(fortran_reader): + """Test the _get_integer_with_optional_kind helper function.""" + code = """subroutine z + real*4 :: x + integer :: y + y = FLOOR(x) + end subroutine z""" + psyir = fortran_reader.psyir_from_source(code) + intrinsic = psyir.walk(IntrinsicCall)[0] + assert _get_integer_with_optional_kind(intrinsic) == INTEGER_TYPE + + code = """subroutine z + real*4 :: x + integer :: y + y = FLOOR(x, kind=4) + end subroutine z""" + + psyir = fortran_reader.psyir_from_source(code) + intrinsic = psyir.walk(IntrinsicCall)[0] + res = _get_integer_with_optional_kind(intrinsic) + assert ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and isinstance(res.precision, Literal) + and res.precision.value == "4" + ) + + +def test_int_return_type(fortran_reader): + """Test the _int_return_type helper function.""" + code = """subroutine z + real*4 :: x + integer :: y + y = INT(x) + end subroutine z""" + psyir = fortran_reader.psyir_from_source(code) + intrinsic = psyir.walk(IntrinsicCall)[0] + assert _int_return_type(intrinsic) == INTEGER_TYPE + + code = """subroutine z + real*4, dimension(100) :: x + integer*8, dimension(100) :: y + y = INT(x, kind=8) + end subroutine z""" + psyir = fortran_reader.psyir_from_source(code) + intrinsic = psyir.walk(IntrinsicCall)[0] + rtype = _int_return_type(intrinsic) + assert isinstance(rtype, ArrayType) + assert rtype.intrinsic == ScalarType.Intrinsic.INTEGER + assert rtype.precision.value == "8" + + +def test_iparity_return_type(fortran_reader): + """Test the _iparity_return_type helper function.""" + code = """ + subroutine x + integer, dimension(100, 100) :: array + integer :: k + k = IPARITY(array) + end subroutine x + """ + psyir = fortran_reader.psyir_from_source(code) + intrinsic = psyir.walk(ArrayReference)[0] + intrinsic = IntrinsicCall.create( + IntrinsicCall.Intrinsic.PARITY, [x.copy() for x in intrinsic.indices] + ) + + assert _iparity_return_type(intrinsic) == INTEGER_TYPE + + # Can't test the other case with fortran reader, so need to + # create it manually. + k_sym = psyir.children[0].symbol_table.lookup("k") + intrinsic = psyir.walk(ArrayReference)[0] + intrinsic = IntrinsicCall.create( + IntrinsicCall.Intrinsic.PARITY, + [intrinsic.indices[0].copy(), Reference(k_sym)], + ) + res = _iparity_return_type(intrinsic) + assert isinstance(res, ArrayType) + assert len(res.shape) == 1 + assert res.shape[0] == ArrayType.Extent.DEFERRED + + +def test_get_bound_function_return_type(fortran_reader): + """Test the _get_bound_function_return_type helper function.""" + code = """subroutine x + integer, dimension(100,100) :: array + integer, dimension(2) :: out1 + integer*8 :: out2 + out1 = LBOUND(array) + out2 = LBOUND(array, dim=1, kind=8) + end subroutine x""" + psyir = fortran_reader.psyir_from_source(code) + intrinsics = psyir.walk(IntrinsicCall) + + res = _get_bound_function_return_type(intrinsics[0]) + assert isinstance(res, ArrayType) + assert len(res.shape) == 1 + assert res.datatype == INTEGER_TYPE + assert res.shape[0].lower.value == "1" + assert res.shape[0].upper.value == "2" + + res = _get_bound_function_return_type(intrinsics[1]) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision.value == "8" + + +def test_get_first_argument_type_with_optional_kind(fortran_reader): + """Test the _get_first_arguemnt_type_with_optional_kind helper + function.""" + code = """subroutine x + logical*4 :: a + logical*8 :: b + b = LOGICAL(a, kind=8) + end subroutine x""" + psyir = fortran_reader.psyir_from_source(code) + intrinsics = psyir.walk(IntrinsicCall) + + res = _get_first_argument_type_with_optional_kind(intrinsics[0]) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.BOOLEAN + assert res.precision.value == "8" + + +def test_get_first_argument_intrinsic_with_optional_kind_and_dim( + fortran_reader, +): + """Test the _get_first_argument_intrinsic_with_optional_kind_and_dim + helper function.""" + code = """subroutine w + integer, dimension(100, 100) :: x + integer, dimension(100) :: y + integer, dimension(:) :: res + integer :: res2 + res = MAXLOC(x) + res = MAXLOC(x, dim=1, kind=8) + res2 = MAXLOC(y, dim=1) + end subroutine w""" + psyir = fortran_reader.psyir_from_source(code) + intrinsics = psyir.walk(IntrinsicCall) + res = _get_first_argument_intrinsic_with_optional_kind_and_dim( + intrinsics[0] + ) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == ScalarType.Precision.UNDEFINED + assert len(res.shape) == 1 + assert res.shape[0].lower.value == "1" + assert res.shape[0].upper.value == "2" + + res = _get_first_argument_intrinsic_with_optional_kind_and_dim( + intrinsics[1] + ) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision.value == "8" + assert len(res.shape) == 1 + assert res.shape[0] == ArrayType.Extent.DEFERRED + + res = _get_first_argument_intrinsic_with_optional_kind_and_dim( + intrinsics[2] + ) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == ScalarType.Precision.UNDEFINED + + +# FIXME Do we need ANINT tests. +@pytest.mark.parametrize( + "code, expected", + [ + ( + """subroutine x complex(4) :: z4 real :: result result = aimag(z4) end subroutine x""", - # AIMAG return type is UnresolvedType - lambda res: isinstance(res, UnresolvedType) - ), - ("""subroutine z + # AIMAG return type is UnresolvedType + lambda res: isinstance(res, UnresolvedType), + ), + ( + """subroutine z real*4 :: x real :: y y = AINT(x) end subroutine z""", - # AINT return type is that of x here. - lambda res: (res.intrinsic == ScalarType.Intrinsic.REAL and - res.precision == 4) - ), - ("""subroutine z + # AINT return type is that of x here. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.REAL + and res.precision == 4 + ), + ), + ( + """subroutine z real*4 :: x real*8 :: y y = AINT(x, kind=8) end subroutine z""", - # AINT return type is REAL with kind 8. - lambda res: (res.intrinsic == ScalarType.Intrinsic.REAL and - isinstance(res.precision, Literal) and - res.precision.value == "8") - ), - ]) + # AINT return type is REAL with kind 8. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.REAL + and isinstance(res.precision, Literal) + and res.precision.value == "8" + ), + ), + ( + """subroutine x + complex(4) :: z4 + real :: r + z4 = CMPLX(r) + end subroutine x""", + # CMPLX return type is UnresolvedType + lambda res: isinstance(res, UnresolvedType), + ), + ( + """subroutine x + complex(4) :: z4 + complex(4) :: r + z4 = CONJG(r) + end subroutine x""", + # CONJG return type is UnresolvedType + lambda res: isinstance(res, UnresolvedType), + ), + ( + """subroutine x + integer :: a(100) + integer :: b(100) + integer :: c + c = DOT_PRODUCT(a,b) + end subroutine x""", + # DOT_PRODUCT RETURN TYPE is Scalar type of input 1. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED + ), + ), + ( + """subroutine z + integer :: i, j, k + k = IAND(i,j) + end subroutine z""", + # Kind is same as first input. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED + ), + ), + ( + """subroutine z + integer*8 :: i, j + j = IAND(1, i) + end subroutine z""", + # Kind is same as 2nd input. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == 8 + ), + ), + ( + """subroutine z + integer :: i, j, k + k = IEOR(i,j) + end subroutine z""", + # Kind is same as first input. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED + ), + ), + ( + """subroutine z + integer*8 :: i, j + j = IEOR(1, i) + end subroutine z""", + # Kind is same as 2nd input. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == 8 + ), + ), + ( + """subroutine z + integer :: i, j + integer :: k + k = IOR(i,j) + end subroutine z""", + # Kind is Integer of first input kind. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED + ), + ), + ( + """subroutine z + integer*8 :: i,j + j = IOR(2, i) + end subroutine z""", + # Result is same as second argument here. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == 8 + ), + ), + ], +) def test_specific_return_types(fortran_reader, code, expected): - ''' Test the specific return types of each IntrinsicCall that has its own - defined return type function.''' + """Test the specific return types of each IntrinsicCall that has its own + defined return type function.""" psyir = fortran_reader.psyir_from_source(code) intrinsic = psyir.walk(IntrinsicCall)[0] assert expected(intrinsic.intrinsic.return_type(intrinsic)) + + +@pytest.mark.parametrize( + "code, intrinsic, expected", + [ + ( + """subroutine test + integer, dimension(100) :: x + integer, dimension(100) :: y + y = coshape(x) + end subroutine test""", + IntrinsicCall.Intrinsic.COSHAPE, + # Return type is integer of kind of x with dimension of x. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED + and len(res.shape) == 1 + and res.shape[0].upper.value == "100" + and res.shape[0].lower.value == "1" + ), + ), + # TODO #2823 Can't do this test yet. + # ("""subroutine test + # integer, dimension(100) :: x + # integer, dimension(100) :: y + # y = coshape(x, kind=4) + # end subroutine test""", + # IntrinsicCall.Intrinsic.COSHAPE, + # # Return type is integer of kind of x with dimension of x. + # lambda res: (res.intrinsic == ScalarType.Intrinsic.INTEGER and + # res.precision.value == "4" and + # len(res.shape) == 1 and res.shape[0].upper.value == "100" + # and res.shape[0].lower.value == "1") + # ), + ( + """subroutine x + integer :: i, j, k + k = DSHIFTL(i,j,4) + end subroutine x""", + IntrinsicCall.Intrinsic.DSHIFTL, + # Return type here is that of input 1. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED + ), + ), + ( + """subroutine x + integer*8 :: j, k + k = DSHIFTL(32,j,4) + end subroutine x""", + IntrinsicCall.Intrinsic.DSHIFTL, + # Return type here is that of input 2. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == 8 + ), + ), + # TODO #2823 Can't do this test yet, PSyclone creates a CodeBlock. + # ("""subroutine x + # integer*8, dimension(100) :: i, j + # i = FAILED_IMAGES() + # end subroutine x""", + # IntrinsicCall.Intrinsic.FAILED_IMAGES, + # # Return type here is Array of deferred size with integer type. + # lambda res: (isinstance(res, ArrayType) and + # res.intrinsic == ScalarType.Intrinsic.INTEGER and + # res.precision == ScalarType.Precision.UNDEFINED) + # ), + # TODO #2823 Can't do this test yet, PSyclone creates a CodeBlock. + # ("""subroutine x + # integer*8, dimension(100) :: i, j + # integer :: bad + # i = FAILED_IMAGES(kind=8) + # end subroutine x""", + # IntrinsicCall.Intrinsic.FAILED_IMAGES, + # # Return type here is Array of deferred size with integer type and + # # kind = 8 + # lambda res: (isinstance(res, ArrayType) and + # res.intrinsic == ScalarType.Intrinsic.INTEGER and + # res.precision.value == "8") + # ), + # TODO #2823 Can't do this test yet, PSyclone creates a CodeBlock. + # ("""subroutine x + # integer :: i + # i = GET_TEAM() + # end subroutine x""", + # IntrinsicCall.Intrinsic.GET_TEAM, + # lambda res: isinstance(res, UnresolvedType) + # ), + ], +) +def test_specific_return_types_incorrect_parsed( + fortran_reader, code, intrinsic, expected +): + """Test the specific return types of IntrisicCalls that aren't recognised + correctly by fparser.""" + psyir = fortran_reader.psyir_from_source(code) + print(psyir.view()) + parsed = psyir.walk(ArrayReference)[0] + indices = [x.copy() for x in parsed.indices] + intr = IntrinsicCall.create(intrinsic, indices) + assert expected(intr.intrinsic.return_type(intr)) From 9f0799f76d30714bad0929404d4ed24e07080e69 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Tue, 2 Sep 2025 16:41:59 +0100 Subject: [PATCH 04/41] [skip-ci] linting --- src/psyclone/tests/psyir/nodes/intrinsic_call_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index d2609a8d1a..3a6cc27a7b 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -1142,7 +1142,8 @@ def test_specific_return_types(fortran_reader, code, expected): # # Return type is integer of kind of x with dimension of x. # lambda res: (res.intrinsic == ScalarType.Intrinsic.INTEGER and # res.precision.value == "4" and - # len(res.shape) == 1 and res.shape[0].upper.value == "100" + # len(res.shape) == 1 and res.shape[0].upper.value + # == "100" # and res.shape[0].lower.value == "1") # ), ( From 5c234ed7d03460dcd0d935bcd5fcbf10d8272334 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 3 Sep 2025 15:15:37 +0100 Subject: [PATCH 05/41] Finished intrinsic return types... --- src/psyclone/psyir/nodes/intrinsic_call.py | 451 ++++++++++++++---- .../tests/psyir/nodes/intrinsic_call_test.py | 368 +++++++++++++- 2 files changed, 728 insertions(+), 91 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 588375edc2..2801f753b1 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -34,6 +34,7 @@ # Author: A. R. Porter, STFC Daresbury Lab # Modified: R. W. Ford, STFC Daresbury Lab # Modified: S. Siso, STFC Daresbury Lab +# Modified: A. B. G. Chalk, STFC Daresbury Lab # ----------------------------------------------------------------------------- """This module contains the IntrinsicCall node implementation.""" @@ -41,8 +42,10 @@ from collections import namedtuple from collections.abc import Iterable from enum import Enum +from typing import Callable from psyclone.core import AccessType, VariablesAccessMap +from psyclone.psyir.nodes.operation import BinaryOperation from psyclone.psyir.nodes.call import Call from psyclone.psyir.nodes.datanode import DataNode from psyclone.psyir.nodes.literal import Literal @@ -59,7 +62,9 @@ ArrayType, ScalarType, UnresolvedType, + NoType, ) +from psyclone.psyir.symbols.datasymbol import DataSymbol # pylint: disable=too-many-branches @@ -157,19 +162,23 @@ def _get_first_argument_intrinsic_with_optional_kind_and_dim(node) -> DataType: return ArrayType(dtype, new_shape) -def _get_first_argument_logical_kind_with_optional_dim(node) -> DataType: +def _get_first_argument_specified_kind_with_optional_dim( + node, intrinsic: ScalarType.Intrinsic = ScalarType.Intrinsic.BOOLEAN + ) -> DataType: """Helper function for the common IntrinsicCall case where the - return type is a Scalar logical with the kind of the first argument, + return type is a Scalar with the kind of the first argument, unless an option dim parameter is given in which case an array with rank is given instead. :param node: The IntrinsicCall whose return type to compute. :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + :param intrinsic: The type of the intrinsic of the resulting datatype. + Default is ScalarType.Intrinsic.BOOLEAN :returns: the computed datatype for the IntrinsicCall. """ dtype = ScalarType( - ScalarType.Intrinsic.BOOLEAN, node.arguments[0].datatype.precision + intrinsic, node.arguments[0].datatype.precision ) if "dim" not in node.argument_names: return dtype @@ -284,15 +293,15 @@ def _findloc_return_type(node) -> DataType: else: dtype = node.arguments[0].datatype.copy() if "dim" in node.argument_names: - if len(node.arguments.shape) == 1: + if len(node.arguments[0].datatype.shape) == 1: return dtype else: # We can't get the sizes correct since we don't know # dim, so use deferred. return ArrayType( dtype, - [ArrayType.Extent.DEFFERED] - * (len(node.arguemtns[0].shape) - 1), + [ArrayType.Extent.DEFERRED] + * (len(node.arguments[0].datatype.shape) - 1), ) else: return ArrayType( @@ -357,14 +366,13 @@ def _iparity_return_type(node) -> DataType: len(node.arguments) == 2 and "mask" in node.argument_names ): return dtype - else: - # We have a dimension specified. We don't know the resultant shape - # in any detail as its dependent on the value of dim - return ArrayType( - dtype, - [ArrayType.Extent.DEFERRED] - * (len(node.arguments[0].datatype.shape) - 1), - ) + # We have a dimension specified. We don't know the resultant shape + # in any detail as its dependent on the value of dim + return ArrayType( + dtype, + [ArrayType.Extent.DEFERRED] + * (len(node.arguments[0].datatype.shape) - 1), + ) def _get_bound_function_return_type(node) -> DataType: @@ -398,6 +406,108 @@ def _get_bound_function_return_type(node) -> DataType: ) +def _matmul_return_type(node) -> DataType: + """Helper function for the return type of MATMUL. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + argtype1 = node.arguments[0].datatype + argtype2 = node.arguments[1].datatype + shape1 = argtype1.shape + shape2 = argtype2.shape + stype1 = ScalarType(argtype1.intrinsic, argtype1.precision) + stype2 = ScalarType(argtype2.intrinsic, argtype2.precision) + # Create a temporary BinaryOperation to use get_result_scalar_type + arg1 = Reference(DataSymbol("a", stype1)) + arg2 = Reference(DataSymbol("b", stype2)) + binop = BinaryOperation.create(BinaryOperation.Operator.MUL, + arg1, arg2) + # TODO - make this a public method? + stype = binop._get_result_scalar_type([stype1, stype2]) + # a11 a12 x b1 = a11*b1 + a12*b2 + # a21 a22 b2 a21*b1 + a22*b2 + # a31 a32 a31*b1 + a32*b2 + # 3 x 2 * 2 x 1 = 3 x 1 + # rank 2 rank 1 rank 1 + if len(shape1) == 1: + extent = IntrinsicCall.create( + IntrinsicCall.Intrinsic.SIZE, + [node.arguments[1].copy(), + ("dim", Literal("1", INTEGER_TYPE))]) + shape = [extent] + elif len(shape2) == 1: + extent = IntrinsicCall.create( + IntrinsicCall.Intrinsic.SIZE, + [node.arguments[0].copy(), + ("dim", Literal("1", INTEGER_TYPE))]) + shape = [extent] + else: + # matrix-matrix. Result is size(arg0, 1) x size(arg1, 2) + extent1 = IntrinsicCall.create( + IntrinsicCall.Intrinsic.SIZE, + [node.arguments[0].copy(), + ("dim", Literal("1", INTEGER_TYPE))]) + extent2 = IntrinsicCall.create( + IntrinsicCall.Intrinsic.SIZE, + [node.arguments[1].copy(), + ("dim", Literal("2", INTEGER_TYPE))]) + shape = [extent1, extent2] + return ArrayType(stype, shape) + + +def _maxval_return_type(node) -> DataType: + """ Helper function for the MAXVAL (and similar) intrinsic return + types. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + dtype = ScalarType(node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision) + if ("dim" not in node.argument_names + or len(node.arguments[0].datatype.shape) == 1): + return dtype + # We have a dimension specified. We don't know the resultant shape + # in any detail as its dependent on the value of dim + return ArrayType( + dtype, + [ArrayType.Extent.DEFERRED] + * (len(node.arguments[0].datatype.shape) - 1), + ) + + +def _reduce_return_type(node) -> DataType: + """ Helper function for the REDUCE intrinsic return type. + + :param node: The IntrinsicCall whose return type to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + + :returns: the computed datatype for the IntrinsicCall. + """ + # Check if we have dim + have_dim = (len(node.arguments) > 2 and + node.argument_names[2] is None) + dtype = ScalarType(node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision) + if not have_dim: + return dtype + if len(node.arguments[0].datatype.shape) == 1: + return dtype + else: + # We can't get the sizes correct since we don't know + # dim, so use deferred. + return ArrayType( + dtype, + [ArrayType.Extent.DEFERRED] + * (len(node.arguments[0].datatype.shape) - 1), + ) + + class IntrinsicCall(Call): """Node representing a call to an intrinsic routine (function or subroutine). This can be found as a standalone statement @@ -575,7 +685,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {"dim": DataNode}, - _get_first_argument_logical_kind_with_optional_dim, + _get_first_argument_specified_kind_with_optional_dim, None, ) ALLOCATED = IAttr( @@ -614,7 +724,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {"dim": DataNode}, - _get_first_argument_logical_kind_with_optional_dim, + _get_first_argument_specified_kind_with_optional_dim, None, ) ASIN = IAttr( @@ -1832,8 +1942,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, DataNode), {}, - # FIXME Implement MATMUL - Andy had? - NotImplementedError, + _matmul_return_type, None, ) MAX = IAttr( @@ -1878,11 +1987,18 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, - None, + _maxval_return_type, None, ) MERGE = IAttr( - "MERGE", True, True, False, ArgDesc(3, 3, DataNode), {}, None, None + "MERGE", + True, + True, + False, + ArgDesc(3, 3, DataNode), + {}, + _get_first_argument_type, + None ) MERGE_BITS = IAttr( "MERGE_BITS", @@ -1891,7 +2007,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(3, 3, DataNode), {}, - None, + _get_first_argument_type, None, ) MIN = IAttr( @@ -1901,7 +2017,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, None, DataNode), {}, - None, + _get_first_argument_type, None, ) MINEXPONENT = IAttr( @@ -1911,7 +2027,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, DataNode), {}, - None, + INTEGER_TYPE, None, ) MINLOC = IAttr( @@ -1926,7 +2042,7 @@ class Intrinsic(IAttr, Enum): "kind": DataNode, "back": DataNode, }, - None, + _get_first_argument_intrinsic_with_optional_kind_and_dim, None, ) MINVAL = IAttr( @@ -1936,11 +2052,18 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, - None, + _maxval_return_type, None, ) MOD = IAttr( - "MOD", True, True, False, ArgDesc(2, 2, DataNode), {}, None, None + "MOD", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + _get_first_argument_type, + None ) MODULO = IAttr( "MODULO", @@ -1949,7 +2072,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, DataNode), {}, - None, + _get_first_argument_type, None, ) MOVE_ALLOC = IAttr( @@ -1979,7 +2102,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, DataNode), {}, - None, + _get_first_argument_type, None, ) NEW_LINE = IAttr( @@ -1989,7 +2112,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {}, - None, + CHARACTER_TYPE, None, ) NINT = IAttr( @@ -1999,7 +2122,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {"kind": DataNode}, - None, + INTEGER_TYPE, None, ) NORM2 = IAttr( @@ -2009,11 +2132,23 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 2, DataNode), {}, - None, + # No kind on NORM2 but this function works for return type. + # FIXME Check this is correct. + _get_first_argument_intrinsic_with_optional_kind_and_dim, None, ) NOT = IAttr( - "NOT", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + "NOT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + lambda node: ScalarType( + ScalarType.Intrinsic.INTEGER, + node.arguments[0].datatype.precision + ), + None ) NULL = IAttr( "NULL", @@ -2022,7 +2157,8 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(0, 0, DataNode), {"mold": DataNode}, - None, + # Returns a dissociated pointed - not supported. + lambda node: UnresolvedType(), None, ) NUM_IMAGES = IAttr( @@ -2032,7 +2168,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(0, 1, DataNode), {}, - None, + INTEGER_TYPE, None, ) OUT_OF_RANGE = IAttr( @@ -2042,7 +2178,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, DataNode), {"round": DataNode}, - None, + BOOLEAN_TYPE, None, ) PACK = IAttr( @@ -2052,7 +2188,12 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, DataNode), {"vector": DataNode}, - None, + lambda node: ArrayType( + ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision), + [ArrayType.Extent.DEFERRED] + ), None, ) PARITY = IAttr( @@ -2062,7 +2203,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 2, DataNode), {}, - None, + _get_first_argument_type, None, ) POPCNT = IAttr( @@ -2072,7 +2213,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {}, - None, + INTEGER_TYPE, None, ) POPPAR = IAttr( @@ -2082,7 +2223,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {}, - None, + INTEGER_TYPE, None, ) PRECISION = IAttr( @@ -2092,7 +2233,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, DataNode), {}, - None, + INTEGER_TYPE, None, ) PRESENT = IAttr( @@ -2102,7 +2243,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, DataNode), {}, - None, + BOOLEAN_TYPE, None, ) PRODUCT = IAttr( @@ -2112,11 +2253,22 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, - None, + lambda node: ( + _get_first_argument_specified_kind_with_optional_dim( + node, node.arguments[0].datatype.intrinsic + ) + ), None, ) RADIX = IAttr( - "RADIX", True, False, True, ArgDesc(1, 1, DataNode), {}, None, None + "RADIX", + True, + False, + True, + ArgDesc(1, 1, DataNode), + {}, + INTEGER_TYPE, + None ) RANDOM_INIT = IAttr( "RANDOM_INIT", @@ -2155,11 +2307,18 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, Reference), {}, - None, + INTEGER_TYPE, None, ) RANK = IAttr( - "RANK", True, False, True, ArgDesc(1, 1, Reference), {}, None, None + "RANK", + True, + False, + True, + ArgDesc(1, 1, Reference), + {}, + INTEGER_TYPE, + None ) REAL = IAttr( "REAL", @@ -2168,7 +2327,16 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, Reference), {"kind": DataNode}, - None, + lambda node: ( + ScalarType( + ScalarType.Intrinsic.REAL, + ( + node.arguments[node.argument_names.index("kind")] + if "kind" in node.argument_names + else node.arguments[0].datatype.precision + ), + ) + ), None, ) REDUCE = IAttr( @@ -2176,9 +2344,9 @@ class Intrinsic(IAttr, Enum): True, False, False, - ArgDesc(2, 3, Reference), + ArgDesc(2, 3, DataNode), {"mask": DataNode, "identity": DataNode, "ordered": DataNode}, - None, + _reduce_return_type, None, ) REPEAT = IAttr( @@ -2188,7 +2356,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {}, - None, + CHARACTER_TYPE, None, ) RESHAPE = IAttr( @@ -2198,7 +2366,9 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {"pad": DataNode, "order": DataNode}, - None, + # I went with unresolved for now as the result depends on + # argument 2 (even the dimensionality). + lambda node: UnresolvedType(), None, ) RRSPACING = IAttr( @@ -2208,7 +2378,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, Reference), {}, - None, + _get_first_argument_type, None, ) SAME_TYPE_AS = IAttr( @@ -2218,7 +2388,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(2, 2, Reference), {}, - None, + BOOLEAN_TYPE, None, ) SCALE = IAttr( @@ -2228,7 +2398,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {}, - None, + _get_first_argument_type, None, ) SCAN = IAttr( @@ -2238,7 +2408,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {"back": DataNode, "kind": DataNode}, - None, + _get_integer_with_optional_kind, None, ) SELECTED_CHAR_KIND = IAttr( @@ -2248,7 +2418,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, Reference), {}, - None, + INTEGER_TYPE, None, ) SELECTED_INT_KIND = IAttr( @@ -2258,7 +2428,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, Reference), {}, - None, + INTEGER_TYPE, None, ) SELECTED_REAL_KIND = IAttr( @@ -2268,7 +2438,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(0, 0, Reference), {"P": DataNode, "R": DataNode, "radix": DataNode}, - None, + INTEGER_TYPE, None, ) SET_EXPONENT = IAttr( @@ -2278,7 +2448,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {}, - None, + _get_first_argument_type, None, ) SHAPE = IAttr( @@ -2288,7 +2458,17 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, Reference), {"kind": DataNode}, - None, + lambda node: ( + ArrayType(ScalarType( + ScalarType.Intrinsic.INTEGER, + (ScalarType.Precision.UNDEFINED if "kind" not in + node.argument_names else + node.arguments[node.argument_names.index("kind")])), + [ArrayType.ArrayBounds( + Literal("1", INTEGER_TYPE), + Literal(str(len(node.arguments[0].datatype.shape)), + INTEGER_TYPE))]) + ), None, ) SHIFTA = IAttr( @@ -2298,7 +2478,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {}, - None, + _get_first_argument_type, None, ) SHIFTL = IAttr( @@ -2308,7 +2488,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {}, - None, + _get_first_argument_type, None, ) SHIFTR = IAttr( @@ -2318,17 +2498,38 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, Reference), {}, - None, + _get_first_argument_type, None, ) SIGN = IAttr( - "SIGN", True, True, False, ArgDesc(2, 2, DataNode), {}, None, None + "SIGN", + True, + True, + False, + ArgDesc(2, 2, DataNode), + {}, + _get_first_argument_type, + None ) SIN = IAttr( - "SIN", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + "SIN", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None ) SINH = IAttr( - "SINH", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + "SINH", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None ) SIZE = IAttr( "SIZE", @@ -2337,7 +2538,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, - None, + _get_integer_with_optional_kind, None, ) SPACING = IAttr( @@ -2347,7 +2548,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {}, - None, + _get_first_argument_type, None, ) SPREAD = IAttr( @@ -2357,11 +2558,28 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(3, 3, DataNode), {}, - None, + lambda node: ArrayType( + ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision), + ([ArrayType.Extent.DEFERRED] * + (len(node.arguments[0].datatype.shape) + 1) + if isinstance(node.arguments[0].datatype, ArrayType) else + [ArrayType.Extent.DEFERRED]) + ), None, ) SQRT = IAttr( - "SQRT", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + "SQRT", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + # FIXME For reviewer - I put unresolved type because it can return + # COMPLEX depending on input. + lambda node: UnresolvedType(), + None ) STOPPED_IMAGES = IAttr( "STOPPED_IMAGES", @@ -2370,7 +2588,10 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(0, 0, DataNode), {"team": DataNode, "kind": DataNode}, - None, + lambda node: ArrayType( + _get_integer_with_optional_kind(node), + [ArrayType.Extent.DEFERRED] + ), None, ) STORAGE_SIZE = IAttr( @@ -2380,7 +2601,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, DataNode), {"kind": DataNode}, - None, + _get_integer_with_optional_kind, None, ) SUM = IAttr( @@ -2388,9 +2609,13 @@ class Intrinsic(IAttr, Enum): True, False, False, + # FIXME Think this is wrong again - 2nd argument can be non-named + # dim? ArgDesc(1, 1, DataNode), {"dim": DataNode, "mask": DataNode}, - None, + lambda node: _get_first_argument_specified_kind_with_optional_dim( + node, node.arguments[0].datatype.intrinsic + ), None, ) SYSTEM_CLOCK = IAttr( @@ -2404,11 +2629,26 @@ class Intrinsic(IAttr, Enum): None, ) TAN = IAttr( - "TAN", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + "TAN", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None ) TANH = IAttr( - "TANH", True, True, False, ArgDesc(1, 1, DataNode), {}, None, None + "TANH", + True, + True, + False, + ArgDesc(1, 1, DataNode), + {}, + _get_first_argument_type, + None ) + # FIXME I'm not sure this exists? TEAM_IMAGE = IAttr( "TEAM_IMAGE", True, @@ -2424,9 +2664,11 @@ class Intrinsic(IAttr, Enum): True, False, False, + # FIXME Again not sure this is correct. Have used unresolved + # type for the return value - can improve it if wanted. ArgDesc(0, 0, DataNode), {"coarray": DataNode, "team": DataNode, "dim": DataNode}, - None, + lambda node: UnresolvedType(), None, ) TINY = IAttr( @@ -2436,7 +2678,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, (Reference, Literal)), {}, - None, + _get_first_argument_type, None, ) TRAILZ = IAttr( @@ -2446,7 +2688,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {}, - None, + INTEGER_TYPE, None, ) TRANSFER = IAttr( @@ -2456,7 +2698,16 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, DataNode), {"size": DataNode}, - None, + lambda node: ( + node.arguments[1].datatype if + ("size" not in node.argument_names and + not isinstance(node.arguments[1].datatype, ArrayType)) + else ArrayType( + ScalarType(node.arguments[1].datatype.intrinsic, + node.arguments[1].datatype.precision), + [ArrayType.Extent.DEFERRED]) + + ), None, ) TRANSPOSE = IAttr( @@ -2466,11 +2717,23 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(1, 1, DataNode), {}, - None, + lambda node: ArrayType(ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision), + [node.arguments[0].datatype.shape[1], + node.arguments[0].datatype.shape[0]] + ), None, ) TRIM = IAttr( - "TRIM", True, False, False, ArgDesc(1, 1, DataNode), {}, None, None + "TRIM", + True, + False, + False, + ArgDesc(1, 1, DataNode), + {}, + CHARACTER_TYPE, + None ) UBOUND = IAttr( "UBOUND", @@ -2479,7 +2742,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, - None, + _get_bound_function_return_type, None, ) UCOBOUND = IAttr( @@ -2489,7 +2752,7 @@ class Intrinsic(IAttr, Enum): True, ArgDesc(1, 1, DataNode), {"dim": DataNode, "kind": DataNode}, - None, + _get_bound_function_return_type, None, ) UNPACK = IAttr( @@ -2499,7 +2762,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(3, 3, DataNode), {}, - None, + _get_first_argument_type, None, ) VERIFY = IAttr( @@ -2509,7 +2772,7 @@ class Intrinsic(IAttr, Enum): False, ArgDesc(2, 2, DataNode), {"back": DataNode, "kind": DataNode}, - None, + _get_integer_with_optional_kind, None, ) @@ -2548,6 +2811,26 @@ def intrinsic(self): """ return self.routine.symbol.intrinsic + @property + def datatype(self) -> DataType: + """Return the datatype of this IntrinsicCall. + + :returns: The datatype corresponding to this IntrinsicCall. + """ + # If the return type is None then return NoType + if not self.intrinsic.return_type: + return NoType() + if isinstance(self.intrinsic.return_type, Callable): + try: + return self.intrinsic.return_type(self) + except Exception: + # If we don't know what a type is correctly then many + # of the computed types will fail, so we should give + # an UnresolvedType in those cases. + return UnresolvedType() + else: + return self.intrinsic.return_type + def is_available_on_device(self, device_string: str = "") -> bool: """ :param device_string: optional string to identify the offloading diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 3a6cc27a7b..03acc37d8b 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -55,7 +55,7 @@ IntrinsicCall, IAttr, _get_first_argument_type, - _get_first_argument_logical_kind_with_optional_dim, + _get_first_argument_specified_kind_with_optional_dim, _get_real_with_argone_kind, _get_real_with_x_kind, _get_integer_of_kind_with_optional_dim, @@ -66,6 +66,9 @@ _get_bound_function_return_type, _get_first_argument_type_with_optional_kind, _get_first_argument_intrinsic_with_optional_kind_and_dim, + _matmul_return_type, + _maxval_return_type, + _reduce_return_type ) from psyclone.psyir.symbols import ( ArrayType, @@ -77,6 +80,7 @@ CHARACTER_TYPE, ScalarType, UnresolvedType, + NoType ) @@ -117,6 +121,36 @@ def test_intrinsiccall_intrinsic(): assert call.intrinsic is IntrinsicCall.Intrinsic.MAXVAL +def test_intrinsiccall_datatype(fortran_reader): + """Test the datatype property returns the correct return types. + """ + call = IntrinsicCall(IntrinsicCall.Intrinsic.NULLIFY) + assert isinstance(call.datatype, NoType) + + code = """subroutine test + integer :: i + i = BIT_SIZE(i) + i = ABS(i) + end subroutine test + """ + psyir = fortran_reader.psyir_from_source(code) + call = psyir.walk(IntrinsicCall)[0] + assert call.datatype == INTEGER_TYPE + + call = psyir.walk(IntrinsicCall)[1] + assert call.datatype == INTEGER_TYPE + + code = """subroutine test + use my_mod + + i = ABS(i) + end subroutine test + """ + psyir = fortran_reader.psyir_from_source(code) + call = psyir.walk(IntrinsicCall)[0] + assert isinstance(call.datatype, UnresolvedType) + + 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 @@ -684,8 +718,8 @@ def test_get_first_argument_type(fortran_reader): assert dtype.precision == ScalarType.Precision.UNDEFINED -def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): - """Test the _get_first_argument_logical_kind_with_optional_dim helper +def test__get_first_argument_specified_kind_with_optional_dim(fortran_reader): + """Test the _get_first_argument_specified_kind_with_optional_dim helper function.""" code = """subroutine x logical, dimension(100,100) :: a @@ -697,10 +731,10 @@ def test_get_first_argument_logical_kind_with_optional_dim(fortran_reader): """ psyir = fortran_reader.psyir_from_source(code) all_calls = psyir.walk(IntrinsicCall) - dtype = _get_first_argument_logical_kind_with_optional_dim(all_calls[0]) + dtype = _get_first_argument_specified_kind_with_optional_dim(all_calls[0]) assert dtype.intrinsic == ScalarType.Intrinsic.BOOLEAN assert dtype.precision == ScalarType.Precision.UNDEFINED - dtype = _get_first_argument_logical_kind_with_optional_dim(all_calls[1]) + dtype = _get_first_argument_specified_kind_with_optional_dim(all_calls[1]) assert isinstance(dtype, ArrayType) assert len(dtype.shape) == 1 assert dtype.shape[0] == ArrayType.Extent.DEFERRED @@ -967,7 +1001,122 @@ def test_get_first_argument_intrinsic_with_optional_kind_and_dim( assert res.precision == ScalarType.Precision.UNDEFINED -# FIXME Do we need ANINT tests. +def test_matmul_return_type(fortran_reader): + code = """subroutine test + real, dimension(100,100) :: a + double precision, dimension(100, 100) :: b + real, dimension(100) :: c + real, dimension(:) :: d + real, dimension(:,:) :: e + + e = MATMUL(a,b) + d = MATMUL(a,c) + d = MATMUL(c,a) + end subroutine test""" + psyir = fortran_reader.psyir_from_source(code) + intrinsics = psyir.walk(IntrinsicCall) + res = _matmul_return_type(intrinsics[0]) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.REAL + assert res.precision == ScalarType.Precision.UNDEFINED + assert len(res.shape) == 2 + assert res.shape[0].lower.value == "1" + assert isinstance(res.shape[0].upper, IntrinsicCall) + assert res.shape[0].upper.intrinsic == IntrinsicCall.Intrinsic.SIZE + assert res.shape[0].upper.arguments[0].symbol.name == "a" + assert res.shape[0].upper.arguments[1].value == "1" + assert res.shape[1].lower.value == "1" + assert isinstance(res.shape[1].upper, IntrinsicCall) + assert res.shape[1].upper.intrinsic == IntrinsicCall.Intrinsic.SIZE + assert res.shape[1].upper.arguments[0].symbol.name == "b" + assert res.shape[1].upper.arguments[1].value == "2" + + res = _matmul_return_type(intrinsics[1]) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.REAL + assert res.precision == ScalarType.Precision.UNDEFINED + assert len(res.shape) == 1 + assert res.shape[0].lower.value == "1" + assert isinstance(res.shape[0].upper, IntrinsicCall) + assert res.shape[0].upper.intrinsic == IntrinsicCall.Intrinsic.SIZE + assert res.shape[0].upper.arguments[0].symbol.name == "a" + assert res.shape[0].upper.arguments[1].value == "1" + + res = _matmul_return_type(intrinsics[2]) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.REAL + assert res.precision == ScalarType.Precision.UNDEFINED + assert len(res.shape) == 1 + assert res.shape[0].lower.value == "1" + assert isinstance(res.shape[0].upper, IntrinsicCall) + assert res.shape[0].upper.intrinsic == IntrinsicCall.Intrinsic.SIZE + assert res.shape[0].upper.arguments[0].symbol.name == "a" + assert res.shape[0].upper.arguments[1].value == "1" + + +def test_maxval_return_type(fortran_reader): + '''Test for the _maxval_return_type function.''' + code = """subroutine test + integer*8, dimension(100,100) :: x + integer, dimension(100) :: z + integer :: y + y = MAXVAL(x) + z = MAXVAL(x, dim=2) + end subroutine test + """ + psyir = fortran_reader.psyir_from_source(code) + intrs = psyir.walk(IntrinsicCall) + + res = _maxval_return_type(intrs[0]) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == 8 + + res = _maxval_return_type(intrs[1]) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == 8 + assert len(res.shape) == 1 + assert res.shape[0] == ArrayType.Extent.DEFERRED + + +def test_reduce_return_type(fortran_reader): + """Test the _reduce_return_type function.""" + code = """subroutine test + integer*8, dimension(100,100) :: x + integer, dimension(100) :: z + integer :: y + y = REDUCE(x, test) + z = REDUCE(x, test, 2) + end subroutine test + """ + psyir = fortran_reader.psyir_from_source(code) + + intrinsic = psyir.walk(ArrayReference)[0] + intrinsic = IntrinsicCall.create( + IntrinsicCall.Intrinsic.REDUCE, + [intrinsic.indices[0].copy(), intrinsic.indices[1].copy()], + ) + res = _reduce_return_type(intrinsic) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == 8 + + intrinsic = psyir.walk(ArrayReference)[1] + intrinsic = IntrinsicCall.create( + IntrinsicCall.Intrinsic.REDUCE, + [intrinsic.indices[0].copy(), intrinsic.indices[1].copy(), + intrinsic.indices[2].copy()], + ) + res = _reduce_return_type(intrinsic) + assert isinstance(res, ArrayType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == 8 + assert len(res.shape) == 1 + assert res.shape[0] == ArrayType.Extent.DEFERRED + + +# FIXME Do we need ANINT (also REAL) tests (Reviewer/codecov decision). @pytest.mark.parametrize( "code, expected", [ @@ -1103,6 +1252,196 @@ def test_get_first_argument_intrinsic_with_optional_kind_and_dim( and res.precision == 8 ), ), + ( + """subroutine z + integer*8 :: i,j + j = NOT(i) + end subroutine z""", + # Result is INTEGER with kind as first argument. + lambda res: ( + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == 8 + ), + ), + ( + """subroutine z + integer, dimension(100) :: i + integer, dimension(100) :: j + logical, dimension(100) :: mask + j = pack(i, mask) + end subroutine z""", + # Result is integer array with unknown size. + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED and + res.shape[0] == ArrayType.Extent.DEFERRED + ), + ), + ( + """subroutine z + real, dimension(100,100) :: i + real :: k + k = PRODUCT(i) + end subroutine z""", + # Result is real scalar. + lambda res: ( + isinstance(res, ScalarType) and + res.intrinsic == ScalarType.Intrinsic.REAL + and res.precision == ScalarType.Precision.UNDEFINED + ), + ), + ( + """subroutine z + real, dimension(100,100) :: i + real, dimension(100) :: k + k = PRODUCT(i, dim=1) + end subroutine z""", + # Result is real array with unknown size. + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.REAL + and res.precision == ScalarType.Precision.UNDEFINED and + res.shape[0] == ArrayType.Extent.DEFERRED + ), + ), + ( + """subroutine z + real*8, dimension(100, 100) :: i + integer, dimension(:) :: k + k = SHAPE(i) + end subroutine z""", + # Result is INTEGER ARRAY with size 2 + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision == ScalarType.Precision.UNDEFINED and + len(res.shape) == 1 and + res.shape[0].lower.value == "1" and + res.shape[0].upper.value == "2" + ) + ), + ( + """subroutine z + real*8, dimension(100, 100) :: i + integer, dimension(:) :: k + k = SHAPE(i, kind=8) + end subroutine z""", + # Result is INTEGER ARRAY with size 2 + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.INTEGER + and res.precision.value == "8" and + len(res.shape) == 1 and + res.shape[0].lower.value == "1" and + res.shape[0].upper.value == "2" + ) + ), + ( + """subroutine z + real*8, dimension(100) :: i + real*8, dimension(:,:) :: k + k = SPREAD(i,1,100) + end subroutine z""", + # Result is real array of dimension 2 + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.REAL + and res.precision == 8 and + len(res.shape) == 2 and + res.shape[0] == ArrayType.Extent.DEFERRED and + res.shape[1] == ArrayType.Extent.DEFERRED + ) + ), + ( + """subroutine z + real*8 :: i + real*8, dimension(:) :: k + k = SPREAD(i,1,100) + end subroutine z""", + # Result is real array of dimension 1 + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.REAL + and res.precision == 8 and + len(res.shape) == 1 and + res.shape[0] == ArrayType.Extent.DEFERRED + ) + ), + ( + """subroutine z + real*8, dimension(100) :: arr + real*8 :: res + res = SUM(arr) + end subroutine z""", + # Result is real scalar. + lambda res: ( + isinstance(res, ScalarType) and + res.intrinsic == ScalarType.Intrinsic.REAL and + res.precision == 8 + ) + ), + ( + """subroutine z + real*8, dimension(100, 100) :: arr + real*8, dimension(:) :: res + res = SUM(arr, dim=1) + end subroutine z""", + # Result is real scalar. + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.REAL and + res.precision == 8 and + len(res.shape) == 1 + and res.shape[0] == ArrayType.Extent.DEFERRED + ) + ), + ( + """subroutine z + real*8, dimension(100, 100) :: arr + real*8, dimension(:) :: res + res = TRANSFER(arr, res) + end subroutine z""", + # Result is real array. + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.REAL and + res.precision == 8 and + len(res.shape) == 1 + and res.shape[0] == ArrayType.Extent.DEFERRED + ) + ), + ( + """subroutine z + real*8, dimension(100, 100) :: arr + real :: res + res = TRANSFER(arr, res) + end subroutine z""", + # Result is scalar real. + lambda res: ( + isinstance(res, ScalarType) and + res.intrinsic == ScalarType.Intrinsic.REAL and + res.precision == ScalarType.Precision.UNDEFINED + ) + ), + ( + """subroutine z + real*8, dimension(100, 10) :: arr + real*8, dimension(10, 100) :: arr2 + arr2 = TRANSPOSE(arr) + end subroutine z""", + # Result is real array (10,100). + lambda res: ( + isinstance(res, ArrayType) and + res.intrinsic == ScalarType.Intrinsic.REAL and + res.precision == 8 and + len(res.shape) == 2 + and res.shape[0].lower.value == "1" + and res.shape[0].upper.value == "10" + and res.shape[1].lower.value == "1" + and res.shape[1].upper.value == "100" + ) + ), ], ) def test_specific_return_types(fortran_reader, code, expected): @@ -1202,6 +1541,22 @@ def test_specific_return_types(fortran_reader, code, expected): # IntrinsicCall.Intrinsic.GET_TEAM, # lambda res: isinstance(res, UnresolvedType) # ), + # TODO #2823 Can't do this test yet, PSyclone creates a CodeBlock. + # ( + # """subroutine z + # integer, dimension(:) :: result + # result = STOPPED_IMAGES() + # end subroutine z""", + # IntrinsicCall.Intrinsic.STOPPED_IMAGES, + # # Result is an integer array of dimension 1 + # lambda res: ( + # isinstance(res, ArrayType) and + # res.intrinsic == ScalarType.Intrinsic.INTEGER + # and res.precision == ScalarType.Precision.UNDEFINED and + # len(res.shape) == 1 and + # res.shape[0] == ArrayType.Extent.DEFERRED + # ) + # ), ], ) def test_specific_return_types_incorrect_parsed( @@ -1210,7 +1565,6 @@ def test_specific_return_types_incorrect_parsed( """Test the specific return types of IntrisicCalls that aren't recognised correctly by fparser.""" psyir = fortran_reader.psyir_from_source(code) - print(psyir.view()) parsed = psyir.walk(ArrayReference)[0] indices = [x.copy() for x in parsed.indices] intr = IntrinsicCall.create(intrinsic, indices) From 08fc22a616808700d72cd5f4aaa8d16538d56ad5 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 3 Sep 2025 16:05:17 +0100 Subject: [PATCH 06/41] Finish failing tests --- src/psyclone/psyir/nodes/intrinsic_call.py | 3265 +++++++++-------- .../tests/psyir/nodes/operation_test.py | 6 +- .../intrinsics/sign2code_trans_test.py | 10 +- 3 files changed, 1654 insertions(+), 1627 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 2801f753b1..1c553f34ad 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -549,124 +549,124 @@ class Intrinsic(IAttr, Enum): # but in PSyIR they are represented as Intrinsics) # TODO 3060 reference_accesses ALLOCATE = IAttr( - "ALLOCATE", - False, - False, - False, - ArgDesc(1, None, Reference), - { + name="ALLOCATE", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, None, Reference), + optional_args={ "mold": Reference, "source": Reference, "stat": Reference, "errmsg": Reference, }, - None, - None, + return_type=None, + reference_accesses=None, ) DEALLOCATE = IAttr( - "DEALLOCATE", - False, - False, - False, - ArgDesc(1, None, Reference), - {"stat": Reference}, - None, - None, + name="DEALLOCATE", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, None, Reference), + optional_args={"stat": Reference}, + return_type=None, + reference_accesses=None, ) NULLIFY = IAttr( - "NULLIFY", - False, - False, - False, - ArgDesc(1, None, Reference), - {}, - None, - None, + name="NULLIFY", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, None, Reference), + optional_args={}, + return_type=None, + reference_accesses=None, ) # Fortran Intrinsics (from Fortran 2018 standard table 16.1) ABS = IAttr( - "ABS", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, + name="ABS", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, # TODO 1590 Complex conversion unsupported. - _get_first_argument_type, - None, + return_type=_get_first_argument_type, + reference_accesses=None, ) ACHAR = IAttr( - "ACHAR", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - CHARACTER_TYPE, - None, + name="ACHAR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=CHARACTER_TYPE, + reference_accesses=None, ) ACOS = IAttr( - "ACOS", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="ACOS", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ACOSH = IAttr( - "ACOSH", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="ACOSH", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ADJUSTL = IAttr( - "ADJUSTL", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, + name="ADJUSTL", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, # TODO 2612 This may be more complex if we support character len - _get_first_argument_type, - None, + return_type=_get_first_argument_type, + reference_accesses=None, ) ADJUSTR = IAttr( - "ADJUSTR", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, + name="ADJUSTR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, # TODO 2612 This may be more complex if we support character len - _get_first_argument_type, - None, + return_type=_get_first_argument_type, + reference_accesses=None, ) AIMAG = IAttr( - "AIMAG", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, + name="AIMAG", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, # TODO #1590 Complex numbers' precision unsupported. - lambda node: UnresolvedType(), - None, + return_type=lambda node: UnresolvedType(), + reference_accesses=None, ) AINT = IAttr( - "AINT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - lambda node: ( + name="AINT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=lambda node: ( ScalarType( ScalarType.Intrinsic.REAL, ( @@ -676,36 +676,36 @@ class Intrinsic(IAttr, Enum): ), ) ), - None, + reference_accesses=None, ) ALL = IAttr( - "ALL", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"dim": DataNode}, - _get_first_argument_specified_kind_with_optional_dim, - None, + name="ALL", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode}, + return_type=_get_first_argument_specified_kind_with_optional_dim, + reference_accesses=None, ) ALLOCATED = IAttr( - "ALLOCATED", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="ALLOCATED", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) ANINT = IAttr( - "ANINT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - lambda node: ( + name="ANINT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=lambda node: ( ScalarType( ScalarType.Intrinsic.REAL, ( @@ -715,442 +715,450 @@ class Intrinsic(IAttr, Enum): ), ) ), - None, + reference_accesses=None, ) ANY = IAttr( - "ANY", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"dim": DataNode}, - _get_first_argument_specified_kind_with_optional_dim, - None, + name="ANY", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode}, + return_type=_get_first_argument_specified_kind_with_optional_dim, + reference_accesses=None, ) ASIN = IAttr( - "ASIN", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="ASIN", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ASINH = IAttr( - "ASINH", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="ASINH", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ASSOCIATED = IAttr( - "ASSOCIATED", - False, - False, - True, - ArgDesc(1, 1, DataNode), - {"target": DataNode}, - BOOLEAN_TYPE, - None, + name="ASSOCIATED", + is_pure=False, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"target": DataNode}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) ATAN = IAttr( - "ATAN", - True, - True, - False, - ArgDesc(1, 2, DataNode), - {}, + name="ATAN", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 2, DataNode), + optional_args={}, # N. B. If this has 2 arguments then the return value # is the of the second argument, however the standard defines # the type and kind type of both arguments must be the same. - _get_first_argument_type, - None, + return_type=_get_first_argument_type, + reference_accesses=None, ) ATAN2 = IAttr( - "ATAN2", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - _get_first_argument_type, - None, + name="ATAN2", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ATANH = IAttr( - "ATANH", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="ATANH", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ATOMIC_ADD = IAttr( - "ATOMIC_ADD", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_ADD", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_AND = IAttr( - "ATOMIC_AND", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_AND", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_CAS = IAttr( - "ATOMIC_CAS", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_CAS", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_DEFINE = IAttr( - "ATOMIC_DEFINE", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_DEFINE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_FETCH_ADD = IAttr( - "ATOMIC_FETCH_ADD", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_FETCH_ADD", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_FETCH_AND = IAttr( - "ATOMIC_FETCH_AND", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_FETCH_AND", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_FETCH_OR = IAttr( - "ATOMIC_FETCH_OR", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_FETCH_OR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_FETCH_XOR = IAttr( - "ATOMIC_FETCH_XOR", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_FETCH_XOR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_OR = IAttr( - "ATOMIC_OR", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_OR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_REF = IAttr( - "ATOMIC_REF", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_REF", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) ATOMIC_XOR = IAttr( - "ATOMIC_XOR", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="ATOMIC_XOR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) BESSEL_J0 = IAttr( - "BESSEL_J0", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_real_with_argone_kind, - None, + name="BESSEL_J0", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_real_with_argone_kind, + reference_accesses=None, ) BESSEL_J1 = IAttr( - "BESSEL_J1", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_real_with_argone_kind, - None, + name="BESSEL_J1", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_real_with_argone_kind, + reference_accesses=None, ) BESSEL_JN = IAttr( - "BESSEL_JN", - True, - None, - False, - ArgDesc(2, 3, DataNode), - {}, - _get_real_with_x_kind, - None, + name="BESSEL_JN", + is_pure=True, + is_elemental=None, + is_inquiry=False, + required_args=ArgDesc(2, 3, DataNode), + optional_args={}, + return_type=_get_real_with_x_kind, + reference_accesses=None, ) BESSEL_Y0 = IAttr( - "BESSEL_Y0", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_real_with_argone_kind, - None, + name="BESSEL_Y0", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_real_with_argone_kind, + reference_accesses=None, ) BESSEL_Y1 = IAttr( - "BESSEL_Y1", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_real_with_argone_kind, - None, + name="BESSEL_Y1", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_real_with_argone_kind, + reference_accesses=None, ) BESSEL_YN = IAttr( - "BESSEL_YN", - True, - None, - False, - ArgDesc(2, 3, DataNode), - {}, - _get_real_with_x_kind, - None, + name="BESSEL_YN", + is_pure=True, + is_elemental=None, + is_inquiry=False, + required_args=ArgDesc(2, 3, DataNode), + optional_args={}, + return_type=_get_real_with_x_kind, + reference_accesses=None, ) BGE = IAttr( - "BGE", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="BGE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) BGT = IAttr( - "BGT", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="BGT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) BIT_SIZE = IAttr( - "BIT_SIZE", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="BIT_SIZE", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) BLE = IAttr( - "BLE", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="BLE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) BLT = IAttr( - "BLT", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="BLT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) BTEST = IAttr( - "BTEST", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="BTEST", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) CEILING = IAttr( - "CEILING", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="CEILING", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) CHAR = IAttr( - "CHAR", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - CHARACTER_TYPE, - None, + name="CHAR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=CHARACTER_TYPE, + reference_accesses=None, ) CMPLX = IAttr( - "CMPLX", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"Y": DataNode, "kind": DataNode}, + name="CMPLX", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"Y": DataNode, "kind": DataNode}, # TODO #1590 Complex numbers unsupported. - lambda node: UnresolvedType(), - None, + return_type=lambda node: UnresolvedType(), + reference_accesses=None, ) CO_BROADCAST = IAttr( - "CO_BROADCAST", - True, - False, - False, - ArgDesc(1, 2, DataNode), - {"stat": DataNode, "errmsg": DataNode}, - None, - None, + name="CO_BROADCAST", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 2, DataNode), + optional_args={"stat": DataNode, "errmsg": DataNode}, + return_type=None, + reference_accesses=None, ) CO_MAX = IAttr( - "CO_MAX", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, - None, + name="CO_MAX", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode}, + return_type=None, + reference_accesses=None, ) CO_MIN = IAttr( - "CO_MIN", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, - None, + name="CO_MIN", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode}, + return_type=None, + reference_accesses=None, ) CO_REDUCE = IAttr( - "CO_REDUCE", - True, - False, - False, - ArgDesc(1, 2, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, - None, + name="CO_REDUCE", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 2, DataNode), + optional_args={"result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode}, + return_type=None, + reference_accesses=None, ) CO_SUM = IAttr( - "CO_SUM", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, - None, - None, + name="CO_SUM", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode}, + return_type=None, + reference_accesses=None, ) COMMAND_ARGUMENT_COUNT = IAttr( - "COMMAND_ARGUMENT_COUNT", - True, - False, - False, - ArgDesc(0, 0, None), - {}, - INTEGER_TYPE, - None, + name="COMMAND_ARGUMENT_COUNT", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, None), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) CONJG = IAttr( - "CONJG", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, + name="CONJG", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, # TODO #1590 Complex numbers unsupported. - lambda node: UnresolvedType(), - None, + return_type=lambda node: UnresolvedType(), + reference_accesses=None, ) COS = IAttr( - "COS", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="COS", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) COSH = IAttr( - "COSH", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="COSH", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) COSHAPE = IAttr( - "COSHAPE", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, + name="COSHAPE", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, # FIXME Return type - lambda node: ArrayType( + return_type=lambda node: ArrayType( ScalarType( ScalarType.Intrinsic.INTEGER, ( @@ -1168,247 +1176,248 @@ class Intrinsic(IAttr, Enum): for index in node.arguments[0].datatype.shape ], ), - None, + reference_accesses=None, ) COUNT = IAttr( - "COUNT", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "kind": DataNode}, - _get_integer_of_kind_with_optional_dim, - None, + name="COUNT", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "kind": DataNode}, + return_type=_get_integer_of_kind_with_optional_dim, + reference_accesses=None, ) CPU_TIME = IAttr( - "CPU_TIME", - False, - False, - False, - ArgDesc(1, 1, DataNode), - {}, - None, - None, + name="CPU_TIME", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=None, + reference_accesses=None, ) CSHIFT = IAttr( - "CSHIFT", - True, - False, - False, - ArgDesc(2, 2, DataNode), - {"dim": DataNode}, - _get_first_argument_type, # FIXME Wait on Sergi reply - None, + name="CSHIFT", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"dim": DataNode}, + return_type=_get_first_argument_type, # FIXME Wait on Sergi reply + reference_accesses=None, ) DATE_AND_TIME = IAttr( - "DATE_AND_TIME", - False, - False, - False, - ArgDesc(0, 0, DataNode), - { + name="DATE_AND_TIME", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={ "date": DataNode, "time": DataNode, "zone": DataNode, "values": DataNode, }, - None, - None, + return_type=None, + reference_accesses=None, ) DBLE = IAttr( - "DBLE", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - REAL_DOUBLE_TYPE, - None, + name="DBLE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=REAL_DOUBLE_TYPE, + reference_accesses=None, ) DIGITS = IAttr( - "DIGITS", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="DIGITS", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) DIM = IAttr( - "DIM", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - _get_first_argument_type, - None, + name="DIM", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) DOT_PRODUCT = IAttr( - "DOT_PRODUCT", - True, - False, - False, - ArgDesc(2, 2, DataNode), - {}, - lambda node: ScalarType( + name="DOT_PRODUCT", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=lambda node: ScalarType( node.arguments[0].datatype.intrinsic, node.arguments[0].datatype.precision, ), - None, + reference_accesses=None, ) DPROD = IAttr( - "DPROD", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - REAL8_TYPE, - None, + name="DPROD", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=REAL8_TYPE, + reference_accesses=None, ) DSHIFTL = IAttr( - "DSHIFTL", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {}, - lambda node: ( + name="DSHIFTL", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={}, + return_type=lambda node: ( node.arguments[0].datatype.copy() if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - None, + reference_accesses=None, ) DSHIFTR = IAttr( - "DSHIFTR", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {}, - lambda node: ( + name="DSHIFTR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={}, + return_type=lambda node: ( node.arguments[0].datatype.copy() if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - None, + reference_accesses=None, ) EOSHIFT = IAttr( - "EOSHIFT", - True, - False, - False, - ArgDesc(2, 2, DataNode), - {"boundary": DataNode, "dim": DataNode}, - _get_first_argument_type, # FIXME Wait for Sergi reply. - None, + name="EOSHIFT", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"boundary": DataNode, "dim": DataNode}, + return_type=_get_first_argument_type, + # FIXME Wait for Sergi reply. + reference_accesses=None, ) EPSILON = IAttr( - "EPSILON", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="EPSILON", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ERF = IAttr( - "ERF", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_real_with_argone_kind, - None, + name="ERF", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_real_with_argone_kind, + reference_accesses=None, ) ERFC = IAttr( - "ERFC", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_real_with_argone_kind, - None, + name="ERFC", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_real_with_argone_kind, + reference_accesses=None, ) ERFC_SCALED = IAttr( - "ERFC_SCALED", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_real_with_argone_kind, - None, + name="ERFC_SCALED", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_real_with_argone_kind, + reference_accesses=None, ) EVENT_QUERY = IAttr( - "EVENT_QUERY", - False, - False, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode}, - None, - None, + name="EVENT_QUERY", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode}, + return_type=None, + reference_accesses=None, ) EXECUTE_COMMAND_LINE = IAttr( - "EXECUTE_COMMAND_LINE", - False, - False, - False, - ArgDesc(2, 2, DataNode), - { + name="EXECUTE_COMMAND_LINE", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={ "wait": DataNode, "exitstat": DataNode, "cmdstat": DataNode, "cmdmsg": DataNode, }, - None, - None, + return_type=None, + reference_accesses=None, ) EXP = IAttr( - "EXP", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="EXP", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) EXPONENT = IAttr( - "EXPONENT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="EXPONENT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) EXTENDS_TYPE_OF = IAttr( - "EXTENDS_TYPE_OF", - True, - False, - True, - ArgDesc(2, 2, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="EXTENDS_TYPE_OF", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) FAILED_IMAGES = IAttr( - "FAILED_IMAGES", - False, - False, - False, - ArgDesc(0, 0, DataNode), - {"team": DataNode, "kind": DataNode}, - lambda node: ArrayType( + name="FAILED_IMAGES", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={"team": DataNode, "kind": DataNode}, + return_type=lambda node: ArrayType( ScalarType( ScalarType.Intrinsic.INTEGER, ( @@ -1419,293 +1428,297 @@ class Intrinsic(IAttr, Enum): ), [ArrayType.Extent.DEFERRED], ), - None, + reference_accesses=None, ) FINDLOC = IAttr( - "FINDLOC", - True, - False, - False, - ArgDesc(2, 3, DataNode), - {"mask": DataNode, "kind": DataNode, "back": DataNode}, - _findloc_return_type, - None, + name="FINDLOC", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 3, DataNode), + optional_args={"mask": DataNode, + "kind": DataNode, + "back": DataNode}, + return_type=_findloc_return_type, + reference_accesses=None, ) FLOAT = IAttr( - "FLOAT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - REAL_TYPE, - None, + name="FLOAT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=REAL_TYPE, + reference_accesses=None, ) FLOOR = IAttr( - "FLOOR", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="FLOOR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) FRACTION = IAttr( - "FRACTION", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="FRACTION", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) GAMMA = IAttr( - "GAMMA", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="GAMMA", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) GET_COMMAND = IAttr( - "GET_COMMAND", - False, - False, - False, - ArgDesc(0, 0, DataNode), - { + name="GET_COMMAND", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={ "command": DataNode, "length": DataNode, "status": DataNode, "errmsg": DataNode, }, - None, - None, + return_type=None, + reference_accesses=None, ) GET_COMMAND_ARGUMENT = IAttr( - "GET_COMMAND_ARGUMENT", - False, - False, - False, - ArgDesc(1, 1, DataNode), - { + name="GET_COMMAND_ARGUMENT", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={ "value": DataNode, "length": DataNode, "status": DataNode, "errmsg": DataNode, }, - None, - None, + return_type=None, + reference_accesses=None, ) GET_ENVIRONMENT_VARIABLE = IAttr( - "GET_ENVIRONMENT_VARIABLE", - False, - False, - False, - ArgDesc(1, 1, DataNode), - { + name="GET_ENVIRONMENT_VARIABLE", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={ "value": DataNode, "length": DataNode, "status": DataNode, "trim_name": DataNode, "errmsg": DataNode, }, - None, - None, + return_type=None, + reference_accesses=None, ) GET_TEAM = IAttr( - "GET_TEAM", - True, - False, - False, - ArgDesc(0, 0, DataNode), - {"level": DataNode}, + name="GET_TEAM", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={"level": DataNode}, # Unsupported return type (TEAM_TYPE from ISO_FORTRAN_ENV). - lambda node: UnresolvedType(), - None, + return_type=lambda node: UnresolvedType(), + reference_accesses=None, ) HUGE = IAttr( - "HUGE", - True, - False, - True, - ArgDesc(1, 1, (Reference, Literal)), - {}, - _get_first_argument_type, - None, + name="HUGE", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, (Reference, Literal)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) HYPOT = IAttr( - "HYPOT", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - _get_first_argument_type, - None, + name="HYPOT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) IACHAR = IAttr( - "IACHAR", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="IACHAR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) IALL = IAttr( - "IALL", - True, - False, - False, + name="IALL", + is_pure=True, + is_elemental=False, + is_inquiry=False, # FIXME Note to reviewer I think this should be - # ArgDesc(1, 2, (DataNode)), {"mask": DataNode} + # required_args=ArgDesc(1, 2, (DataNode)), + # optional_args={"mask": DataNode} # See https://gcc.gnu.org/onlinedocs/gfortran/IALL.html # If this changes and "dim" is no longer a named argument, the # return type function will not be correct. - ArgDesc(1, 1, (DataNode)), - {"dim": DataNode, "mask": DataNode}, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"dim": DataNode, "mask": DataNode}, # There is no kind, but this call will work. - _get_integer_of_kind_with_optional_dim, - None, + return_type=_get_integer_of_kind_with_optional_dim, + reference_accesses=None, ) IAND = IAttr( - "IAND", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - lambda node: ( + name="IAND", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=lambda node: ( node.arguments[0].datatype.copy() if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - None, + reference_accesses=None, ) IANY = IAttr( - "IANY", - True, - False, - False, + name="IANY", + is_pure=True, + is_elemental=False, + is_inquiry=False, # FIXME Note to reviewer I think this should be - # ArgDesc(1, 2, (DataNode)), {"mask": DataNode} + # required_args=ArgDesc(1, 2, (DataNode)), + # optional_args={"mask": DataNode} # See https://gcc.gnu.org/onlinedocs/gfortran/IANY.html # If this changes and "dim" is no longer a named argument, the # return type function will not be correct. - ArgDesc(1, 1, (DataNode)), - {"dim": DataNode, "mask": DataNode}, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"dim": DataNode, "mask": DataNode}, # There is no kind, but this call will work. - _get_integer_of_kind_with_optional_dim, - None, + return_type=_get_integer_of_kind_with_optional_dim, + reference_accesses=None, ) IBCLR = IAttr( - "IBCLR", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - _get_first_argument_type, - None, + name="IBCLR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) IBITS = IAttr( - "IBITS", - True, - True, - False, - ArgDesc(3, 3, (DataNode)), - {}, - _get_first_argument_type, - None, + name="IBITS", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) IBSET = IAttr( - "IBSET", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - _get_first_argument_type, - None, + name="IBSET", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ICHAR = IAttr( - "ICHAR", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="ICHAR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) IEOR = IAttr( - "IEOR", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - lambda node: ( + name="IEOR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=lambda node: ( node.arguments[0].datatype.copy() if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - None, + reference_accesses=None, ) IMAGE_INDEX = IAttr( - "IMAGE_INDEX", - True, - False, - True, - ArgDesc(2, 3, (DataNode)), - {}, - INTEGER_TYPE, - None, + name="IMAGE_INDEX", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(2, 3, (DataNode)), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) IMAGE_STATUS = IAttr( - "IMAGE_STATUS", - True, - False, - False, - ArgDesc(1, 1, (DataNode)), - {"team": DataNode}, - INTEGER_TYPE, - None, + name="IMAGE_STATUS", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"team": DataNode}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) INDEX = IAttr( - "INDEX", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {"back": DataNode, "kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="INDEX", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={"back": DataNode, "kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) INT = IAttr( - "INT", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _int_return_type, - None, + name="INT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_int_return_type, + reference_accesses=None, ) IOR = IAttr( - "IOR", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - lambda node: ScalarType( + name="IOR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=lambda node: ScalarType( ScalarType.Intrinsic.INTEGER, ( node.arguments[0].datatype.precision @@ -1713,621 +1726,627 @@ class Intrinsic(IAttr, Enum): else node.arguments[1].datatype.precision ), ), - None, + reference_accesses=None, ) IPARITY = IAttr( - "IPARITY", - True, - False, - False, - ArgDesc(1, 2, (DataNode)), - {"mask": DataNode}, - _iparity_return_type, - None, + name="IPARITY", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 2, (DataNode)), + optional_args={"mask": DataNode}, + return_type=_iparity_return_type, + reference_accesses=None, ) IS_CONTIGUOUS = IAttr( - "IS_CONTIGUOUS", - True, - False, - True, - ArgDesc(1, 1, (DataNode)), - {}, - BOOLEAN_TYPE, - None, + name="IS_CONTIGUOUS", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) IS_IOSTAT_END = IAttr( - "IS_IOSTAT_END", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {}, - BOOLEAN_TYPE, - None, + name="IS_IOSTAT_END", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) IS_IOSTAT_EOR = IAttr( - "IS_IOSTAT_EOR", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {}, - BOOLEAN_TYPE, - None, + name="IS_IOSTAT_EOR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) ISHFT = IAttr( - "ISHFT", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - _get_first_argument_type, - None, + name="ISHFT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) ISHFTC = IAttr( - "ISHFTC", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {"size": DataNode}, - _get_first_argument_type, - None, + name="ISHFTC", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={"size": DataNode}, + return_type=_get_first_argument_type, + reference_accesses=None, ) KIND = IAttr( - "KIND", - True, - False, - True, - ArgDesc(1, 1, (DataNode)), - {}, - INTEGER_TYPE, - None, + name="KIND", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) LBOUND = IAttr( - "LBOUND", - True, - False, - True, - ArgDesc(1, 1, (DataNode)), - {"dim": DataNode, "kind": DataNode}, - _get_bound_function_return_type, - None, + name="LBOUND", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"dim": DataNode, "kind": DataNode}, + return_type=_get_bound_function_return_type, + reference_accesses=None, ) LCOBOUND = IAttr( - "LCOBOUND", - True, - False, - True, - ArgDesc(1, 1, (DataNode)), - {"dim": DataNode, "kind": DataNode}, - _get_bound_function_return_type, - None, + name="LCOBOUND", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"dim": DataNode, "kind": DataNode}, + return_type=_get_bound_function_return_type, + reference_accesses=None, ) LEADZ = IAttr( - "LEADZ", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {}, - INTEGER_TYPE, - None, + name="LEADZ", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) LEN = IAttr( - "LEN", - True, - False, - True, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="LEN", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) LEN_TRIM = IAttr( - "LEN_TRIM", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="LEN_TRIM", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) LGE = IAttr( - "LGE", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - BOOLEAN_TYPE, - None, + name="LGE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) LGT = IAttr( - "LGT", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - BOOLEAN_TYPE, - None, + name="LGT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) LLE = IAttr( - "LLE", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - BOOLEAN_TYPE, - None, + name="LLE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) LLT = IAttr( - "LLT", - True, - True, - False, - ArgDesc(2, 2, (DataNode)), - {}, - BOOLEAN_TYPE, - None, + name="LLT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, (DataNode)), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) LOG = IAttr( - "LOG", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {}, - _get_first_argument_type, - None, + name="LOG", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) LOG_GAMMA = IAttr( - "LOG_GAMMA", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {}, - _get_first_argument_type, - None, + name="LOG_GAMMA", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) LOG10 = IAttr( - "LOG10", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {}, - _get_first_argument_type, - None, + name="LOG10", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) LOGICAL = IAttr( - "LOGICAL", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _get_first_argument_type_with_optional_kind, - None, + name="LOGICAL", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_get_first_argument_type_with_optional_kind, + reference_accesses=None, ) MASKL = IAttr( - "MASKL", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="MASKL", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) MASKR = IAttr( - "MASKR", - True, - True, - False, - ArgDesc(1, 1, (DataNode)), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="MASKR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, (DataNode)), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) MATMUL = IAttr( - "MATMUL", - True, - False, - False, - ArgDesc(2, 2, DataNode), - {}, - _matmul_return_type, - None, + name="MATMUL", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=_matmul_return_type, + reference_accesses=None, ) MAX = IAttr( - "MAX", - True, - True, - False, - ArgDesc(2, None, DataNode), - {}, - _get_first_argument_type, - None, + name="MAX", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, None, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) MAXEXPONENT = IAttr( - "MAXEXPONENT", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="MAXEXPONENT", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) MAXLOC = IAttr( - "MAXLOC", - True, - False, - False, - ArgDesc(1, 2, DataNode), - { + name="MAXLOC", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 2, DataNode), + optional_args={ "dim": DataNode, "mask": DataNode, "kind": DataNode, "back": DataNode, }, - _get_first_argument_intrinsic_with_optional_kind_and_dim, - None, + return_type=( + _get_first_argument_intrinsic_with_optional_kind_and_dim + ), + reference_accesses=None, ) MAXVAL = IAttr( - "MAXVAL", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}, - _maxval_return_type, - None, + name="MAXVAL", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "mask": DataNode}, + return_type=_maxval_return_type, + reference_accesses=None, ) MERGE = IAttr( - "MERGE", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {}, - _get_first_argument_type, - None + name="MERGE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None ) MERGE_BITS = IAttr( - "MERGE_BITS", - True, - True, - False, - ArgDesc(3, 3, DataNode), - {}, - _get_first_argument_type, - None, + name="MERGE_BITS", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) MIN = IAttr( - "MIN", - True, - True, - False, - ArgDesc(2, None, DataNode), - {}, - _get_first_argument_type, - None, + name="MIN", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, None, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) MINEXPONENT = IAttr( - "MINEXPONENT", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="MINEXPONENT", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) MINLOC = IAttr( - "MINLOC", - True, - False, - False, - ArgDesc(1, 2, DataNode), - { + name="MINLOC", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 2, DataNode), + optional_args={ "dim": DataNode, "mask": DataNode, "kind": DataNode, "back": DataNode, }, - _get_first_argument_intrinsic_with_optional_kind_and_dim, - None, + return_type=( + _get_first_argument_intrinsic_with_optional_kind_and_dim + ), + reference_accesses=None, ) MINVAL = IAttr( - "MINVAL", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}, - _maxval_return_type, - None, + name="MINVAL", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "mask": DataNode}, + return_type=_maxval_return_type, + reference_accesses=None, ) MOD = IAttr( - "MOD", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - _get_first_argument_type, - None + name="MOD", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None ) MODULO = IAttr( - "MODULO", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - _get_first_argument_type, - None, + name="MODULO", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) MOVE_ALLOC = IAttr( - "MOVE_ALLOC", - False, - False, - False, - ArgDesc(2, 2, DataNode), - {"stat": DataNode, "errmsg": DataNode}, - None, - None, + name="MOVE_ALLOC", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"stat": DataNode, "errmsg": DataNode}, + return_type=None, + reference_accesses=None, ) MVBITS = IAttr( - "MVBITS", - True, - True, - False, - ArgDesc(5, 5, DataNode), - {}, - None, - None, + name="MVBITS", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(5, 5, DataNode), + optional_args={}, + return_type=None, + reference_accesses=None, ) NEAREST = IAttr( - "NEAREST", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - _get_first_argument_type, - None, + name="NEAREST", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) NEW_LINE = IAttr( - "NEW_LINE", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - CHARACTER_TYPE, - None, + name="NEW_LINE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=CHARACTER_TYPE, + reference_accesses=None, ) NINT = IAttr( - "NINT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - INTEGER_TYPE, - None, + name="NINT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) NORM2 = IAttr( - "NORM2", - True, - False, - False, - ArgDesc(1, 2, DataNode), - {}, + name="NORM2", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 2, DataNode), + optional_args={}, # No kind on NORM2 but this function works for return type. # FIXME Check this is correct. - _get_first_argument_intrinsic_with_optional_kind_and_dim, - None, + return_type=( + _get_first_argument_intrinsic_with_optional_kind_and_dim + ), + reference_accesses=None, ) NOT = IAttr( - "NOT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - lambda node: ScalarType( + name="NOT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=lambda node: ScalarType( ScalarType.Intrinsic.INTEGER, node.arguments[0].datatype.precision ), - None + reference_accesses=None ) NULL = IAttr( - "NULL", - True, - False, - False, - ArgDesc(0, 0, DataNode), - {"mold": DataNode}, + name="NULL", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={"mold": DataNode}, # Returns a dissociated pointed - not supported. - lambda node: UnresolvedType(), - None, + return_type=lambda node: UnresolvedType(), + reference_accesses=None, ) NUM_IMAGES = IAttr( - "NUM_IMAGES", - True, - False, - False, - ArgDesc(0, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="NUM_IMAGES", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) OUT_OF_RANGE = IAttr( - "OUT_OF_RANGE", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"round": DataNode}, - BOOLEAN_TYPE, - None, + name="OUT_OF_RANGE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"round": DataNode}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) PACK = IAttr( - "PACK", - True, - False, - False, - ArgDesc(2, 2, DataNode), - {"vector": DataNode}, - lambda node: ArrayType( + name="PACK", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"vector": DataNode}, + return_type=lambda node: ArrayType( ScalarType( node.arguments[0].datatype.intrinsic, node.arguments[0].datatype.precision), [ArrayType.Extent.DEFERRED] ), - None, + reference_accesses=None, ) PARITY = IAttr( - "PARITY", - True, - False, - False, - ArgDesc(1, 2, DataNode), - {}, - _get_first_argument_type, - None, + name="PARITY", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 2, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) POPCNT = IAttr( - "POPCNT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="POPCNT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) POPPAR = IAttr( - "POPPAR", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="POPPAR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) PRECISION = IAttr( - "PRECISION", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="PRECISION", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) PRESENT = IAttr( - "PRESENT", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - BOOLEAN_TYPE, - None, + name="PRESENT", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) PRODUCT = IAttr( - "PRODUCT", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}, - lambda node: ( + name="PRODUCT", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "mask": DataNode}, + return_type=lambda node: ( _get_first_argument_specified_kind_with_optional_dim( node, node.arguments[0].datatype.intrinsic ) ), - None, + reference_accesses=None, ) RADIX = IAttr( - "RADIX", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None + name="RADIX", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None ) RANDOM_INIT = IAttr( - "RANDOM_INIT", - False, - False, - False, - ArgDesc(2, 2, DataNode), - {}, - None, - None, + name="RANDOM_INIT", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=None, + reference_accesses=None, ) RANDOM_NUMBER = IAttr( - "RANDOM_NUMBER", - False, - False, - False, - ArgDesc(1, 1, Reference), - {}, - None, - None, + name="RANDOM_NUMBER", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, Reference), + optional_args={}, + return_type=None, + reference_accesses=None, ) RANDOM_SEED = IAttr( - "RANDOM_SEED", - False, - False, - False, - ArgDesc(0, 0, Reference), - {"size": DataNode, "put": DataNode, "Get": DataNode}, - None, - None, + name="RANDOM_SEED", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, Reference), + optional_args={"size": DataNode, "put": DataNode, "Get": DataNode}, + return_type=None, + reference_accesses=None, ) RANGE = IAttr( - "RANGE", - True, - False, - True, - ArgDesc(1, 1, Reference), - {}, - INTEGER_TYPE, - None, + name="RANGE", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, Reference), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) RANK = IAttr( - "RANK", - True, - False, - True, - ArgDesc(1, 1, Reference), - {}, - INTEGER_TYPE, - None + name="RANK", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, Reference), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None ) REAL = IAttr( - "REAL", - True, - True, - False, - ArgDesc(1, 1, Reference), - {"kind": DataNode}, - lambda node: ( + name="REAL", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, Reference), + optional_args={"kind": DataNode}, + return_type=lambda node: ( ScalarType( ScalarType.Intrinsic.REAL, ( @@ -2337,128 +2356,130 @@ class Intrinsic(IAttr, Enum): ), ) ), - None, + reference_accesses=None, ) REDUCE = IAttr( - "REDUCE", - True, - False, - False, - ArgDesc(2, 3, DataNode), - {"mask": DataNode, "identity": DataNode, "ordered": DataNode}, - _reduce_return_type, - None, + name="REDUCE", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 3, DataNode), + optional_args={"mask": DataNode, + "identity": DataNode, + "ordered": DataNode}, + return_type=_reduce_return_type, + reference_accesses=None, ) REPEAT = IAttr( - "REPEAT", - True, - False, - False, - ArgDesc(2, 2, Reference), - {}, - CHARACTER_TYPE, - None, + name="REPEAT", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={}, + return_type=CHARACTER_TYPE, + reference_accesses=None, ) RESHAPE = IAttr( - "RESHAPE", - True, - False, - False, - ArgDesc(2, 2, Reference), - {"pad": DataNode, "order": DataNode}, + name="RESHAPE", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={"pad": DataNode, "order": DataNode}, # I went with unresolved for now as the result depends on # argument 2 (even the dimensionality). - lambda node: UnresolvedType(), - None, + return_type=lambda node: UnresolvedType(), + reference_accesses=None, ) RRSPACING = IAttr( - "RRSPACING", - True, - True, - False, - ArgDesc(1, 1, Reference), - {}, - _get_first_argument_type, - None, + name="RRSPACING", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, Reference), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) SAME_TYPE_AS = IAttr( - "SAME_TYPE_AS", - True, - False, - True, - ArgDesc(2, 2, Reference), - {}, - BOOLEAN_TYPE, - None, + name="SAME_TYPE_AS", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(2, 2, Reference), + optional_args={}, + return_type=BOOLEAN_TYPE, + reference_accesses=None, ) SCALE = IAttr( - "SCALE", - True, - True, - False, - ArgDesc(2, 2, Reference), - {}, - _get_first_argument_type, - None, + name="SCALE", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) SCAN = IAttr( - "SCAN", - True, - True, - False, - ArgDesc(2, 2, Reference), - {"back": DataNode, "kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="SCAN", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={"back": DataNode, "kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) SELECTED_CHAR_KIND = IAttr( - "SELECTED_CHAR_KIND", - True, - False, - False, - ArgDesc(1, 1, Reference), - {}, - INTEGER_TYPE, - None, + name="SELECTED_CHAR_KIND", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, Reference), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) SELECTED_INT_KIND = IAttr( - "SELECTED_INT_KIND", - True, - False, - False, - ArgDesc(1, 1, Reference), - {}, - INTEGER_TYPE, - None, + name="SELECTED_INT_KIND", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, Reference), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) SELECTED_REAL_KIND = IAttr( - "SELECTED_REAL_KIND", - True, - False, - False, - ArgDesc(0, 0, Reference), - {"P": DataNode, "R": DataNode, "radix": DataNode}, - INTEGER_TYPE, - None, + name="SELECTED_REAL_KIND", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, Reference), + optional_args={"P": DataNode, "R": DataNode, "radix": DataNode}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) SET_EXPONENT = IAttr( - "SET_EXPONENT", - True, - True, - False, - ArgDesc(2, 2, Reference), - {}, - _get_first_argument_type, - None, + name="SET_EXPONENT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) SHAPE = IAttr( - "SHAPE", - True, - False, - True, - ArgDesc(1, 1, Reference), - {"kind": DataNode}, - lambda node: ( + name="SHAPE", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, Reference), + optional_args={"kind": DataNode}, + return_type=lambda node: ( ArrayType(ScalarType( ScalarType.Intrinsic.INTEGER, (ScalarType.Precision.UNDEFINED if "kind" not in @@ -2469,96 +2490,96 @@ class Intrinsic(IAttr, Enum): Literal(str(len(node.arguments[0].datatype.shape)), INTEGER_TYPE))]) ), - None, + reference_accesses=None, ) SHIFTA = IAttr( - "SHIFTA", - True, - True, - False, - ArgDesc(2, 2, Reference), - {}, - _get_first_argument_type, - None, + name="SHIFTA", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) SHIFTL = IAttr( - "SHIFTL", - True, - True, - False, - ArgDesc(2, 2, Reference), - {}, - _get_first_argument_type, - None, + name="SHIFTL", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) SHIFTR = IAttr( - "SHIFTR", - True, - True, - False, - ArgDesc(2, 2, Reference), - {}, - _get_first_argument_type, - None, + name="SHIFTR", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, Reference), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) SIGN = IAttr( - "SIGN", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {}, - _get_first_argument_type, - None + name="SIGN", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None ) SIN = IAttr( - "SIN", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None + name="SIN", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None ) SINH = IAttr( - "SINH", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None + name="SINH", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None ) SIZE = IAttr( - "SIZE", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="SIZE", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) SPACING = IAttr( - "SPACING", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None, + name="SPACING", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) SPREAD = IAttr( - "SPREAD", - True, - False, - False, - ArgDesc(3, 3, DataNode), - {}, - lambda node: ArrayType( + name="SPREAD", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={}, + return_type=lambda node: ArrayType( ScalarType( node.arguments[0].datatype.intrinsic, node.arguments[0].datatype.precision), @@ -2567,138 +2588,144 @@ class Intrinsic(IAttr, Enum): if isinstance(node.arguments[0].datatype, ArrayType) else [ArrayType.Extent.DEFERRED]) ), - None, + reference_accesses=None, ) SQRT = IAttr( - "SQRT", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, + name="SQRT", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, # FIXME For reviewer - I put unresolved type because it can return # COMPLEX depending on input. - lambda node: UnresolvedType(), - None + return_type=lambda node: UnresolvedType(), + reference_accesses=None ) STOPPED_IMAGES = IAttr( - "STOPPED_IMAGES", - False, - False, - False, - ArgDesc(0, 0, DataNode), - {"team": DataNode, "kind": DataNode}, - lambda node: ArrayType( + name="STOPPED_IMAGES", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={"team": DataNode, "kind": DataNode}, + return_type=lambda node: ArrayType( _get_integer_with_optional_kind(node), [ArrayType.Extent.DEFERRED] ), - None, + reference_accesses=None, ) STORAGE_SIZE = IAttr( - "STORAGE_SIZE", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {"kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="STORAGE_SIZE", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) SUM = IAttr( - "SUM", - True, - False, - False, + name="SUM", + is_pure=True, + is_elemental=False, + is_inquiry=False, # FIXME Think this is wrong again - 2nd argument can be non-named # dim? - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "mask": DataNode}, - lambda node: _get_first_argument_specified_kind_with_optional_dim( - node, node.arguments[0].datatype.intrinsic + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "mask": DataNode}, + return_type=lambda node: ( + _get_first_argument_specified_kind_with_optional_dim( + node, node.arguments[0].datatype.intrinsic + ) ), - None, + reference_accesses=None, ) SYSTEM_CLOCK = IAttr( - "SYSTEM_CLOCK", - False, - False, - False, - ArgDesc(0, 0, DataNode), - {"count": DataNode, "count_rate": DataNode, "count_max": DataNode}, - None, - None, + name="SYSTEM_CLOCK", + is_pure=False, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={"count": DataNode, + "count_rate": DataNode, + "count_max": DataNode}, + return_type=None, + reference_accesses=None, ) TAN = IAttr( - "TAN", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None + name="TAN", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None ) TANH = IAttr( - "TANH", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - _get_first_argument_type, - None + name="TANH", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None ) # FIXME I'm not sure this exists? TEAM_IMAGE = IAttr( - "TEAM_IMAGE", - True, - False, - False, - ArgDesc(0, 0, DataNode), - {"team": DataNode}, - None, - None, + name="TEAM_IMAGE", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(0, 0, DataNode), + optional_args={"team": DataNode}, + return_type=None, + reference_accesses=None, ) THIS_IMAGE = IAttr( - "THIS_IMAGE", - True, - False, - False, + name="THIS_IMAGE", + is_pure=True, + is_elemental=False, + is_inquiry=False, # FIXME Again not sure this is correct. Have used unresolved # type for the return value - can improve it if wanted. - ArgDesc(0, 0, DataNode), - {"coarray": DataNode, "team": DataNode, "dim": DataNode}, - lambda node: UnresolvedType(), - None, + required_args=ArgDesc(0, 0, DataNode), + optional_args={"coarray": DataNode, + "team": DataNode, + "dim": DataNode}, + return_type=lambda node: UnresolvedType(), + reference_accesses=None, ) TINY = IAttr( - "TINY", - True, - False, - True, - ArgDesc(1, 1, (Reference, Literal)), - {}, - _get_first_argument_type, - None, + name="TINY", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, (Reference, Literal)), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) TRAILZ = IAttr( - "TRAILZ", - True, - True, - False, - ArgDesc(1, 1, DataNode), - {}, - INTEGER_TYPE, - None, + name="TRAILZ", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=INTEGER_TYPE, + reference_accesses=None, ) TRANSFER = IAttr( - "TRANSFER", - True, - False, - False, - ArgDesc(2, 2, DataNode), - {"size": DataNode}, - lambda node: ( + name="TRANSFER", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"size": DataNode}, + return_type=lambda node: ( node.arguments[1].datatype if ("size" not in node.argument_names and not isinstance(node.arguments[1].datatype, ArrayType)) @@ -2708,72 +2735,72 @@ class Intrinsic(IAttr, Enum): [ArrayType.Extent.DEFERRED]) ), - None, + reference_accesses=None, ) TRANSPOSE = IAttr( - "TRANSPOSE", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {}, - lambda node: ArrayType(ScalarType( + name="TRANSPOSE", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=lambda node: ArrayType(ScalarType( node.arguments[0].datatype.intrinsic, node.arguments[0].datatype.precision), [node.arguments[0].datatype.shape[1], node.arguments[0].datatype.shape[0]] ), - None, + reference_accesses=None, ) TRIM = IAttr( - "TRIM", - True, - False, - False, - ArgDesc(1, 1, DataNode), - {}, - CHARACTER_TYPE, - None + name="TRIM", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(1, 1, DataNode), + optional_args={}, + return_type=CHARACTER_TYPE, + reference_accesses=None ) UBOUND = IAttr( - "UBOUND", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "kind": DataNode}, - _get_bound_function_return_type, - None, + name="UBOUND", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "kind": DataNode}, + return_type=_get_bound_function_return_type, + reference_accesses=None, ) UCOBOUND = IAttr( - "UCOBOUND", - True, - False, - True, - ArgDesc(1, 1, DataNode), - {"dim": DataNode, "kind": DataNode}, - _get_bound_function_return_type, - None, + name="UCOBOUND", + is_pure=True, + is_elemental=False, + is_inquiry=True, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode, "kind": DataNode}, + return_type=_get_bound_function_return_type, + reference_accesses=None, ) UNPACK = IAttr( - "UNPACK", - True, - False, - False, - ArgDesc(3, 3, DataNode), - {}, - _get_first_argument_type, - None, + name="UNPACK", + is_pure=True, + is_elemental=False, + is_inquiry=False, + required_args=ArgDesc(3, 3, DataNode), + optional_args={}, + return_type=_get_first_argument_type, + reference_accesses=None, ) VERIFY = IAttr( - "VERIFY", - True, - True, - False, - ArgDesc(2, 2, DataNode), - {"back": DataNode, "kind": DataNode}, - _get_integer_with_optional_kind, - None, + name="VERIFY", + is_pure=True, + is_elemental=True, + is_inquiry=False, + required_args=ArgDesc(2, 2, DataNode), + optional_args={"back": DataNode, "kind": DataNode}, + return_type=_get_integer_with_optional_kind, + reference_accesses=None, ) def __hash__(self): diff --git a/src/psyclone/tests/psyir/nodes/operation_test.py b/src/psyclone/tests/psyir/nodes/operation_test.py index c091744a56..438fba021d 100644 --- a/src/psyclone/tests/psyir/nodes/operation_test.py +++ b/src/psyclone/tests/psyir/nodes/operation_test.py @@ -533,9 +533,6 @@ def test_binaryoperation_intrinsic_fn_datatype(): Check that we can get the datatype of an operation involving the result of an intrinsic function. - TODO #1799 - this just returns UnresolvedType at the minute and needs - implementing. - ''' arrtype = ArrayType(REAL_SINGLE_TYPE, [10, 5]) aref = Reference(DataSymbol("array", arrtype)) @@ -543,7 +540,8 @@ def test_binaryoperation_intrinsic_fn_datatype(): arg2 = Reference(DataSymbol("scalar", INTEGER_SINGLE_TYPE)) oper = BinaryOperation.Operator.ADD binop = BinaryOperation.create(oper, arg1, arg2) - assert isinstance(binop.datatype, UnresolvedType) + assert isinstance(binop.datatype, ScalarType) + assert binop.datatype == REAL_SINGLE_TYPE # Test UnaryOperation class diff --git a/src/psyclone/tests/psyir/transformations/intrinsics/sign2code_trans_test.py b/src/psyclone/tests/psyir/transformations/intrinsics/sign2code_trans_test.py index e2627cb139..8d3d177de6 100644 --- a/src/psyclone/tests/psyir/transformations/intrinsics/sign2code_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/intrinsics/sign2code_trans_test.py @@ -293,12 +293,13 @@ def test_sign_of_unknown_type(fortran_reader): ''' code = '''\ program test_prog + use my_mod, only: thing integer, parameter :: wp = kind(1.0d0) integer, parameter, dimension(0:4) :: A2D = (/1, 2, 3, 4, 5/) REAL(wp), DIMENSION(A2D(0)) :: ztmp1 ztmp1 = 0.0 - ! Can't handle because we don't know the type of MAX or ABS - ztmp1 = SIGN( MAX(ABS(ztmp1),1.E-6_wp), ztmp1 ) + ! Can't handle because we don't know the type of thing + ztmp1 = SIGN( thing, ztmp1 ) ! Can't handle because ztmp1 is an array ztmp1 = SIGN( ztmp1, 1.0 ) end program test_prog''' @@ -308,8 +309,9 @@ def test_sign_of_unknown_type(fortran_reader): if call.intrinsic.name == "SIGN"] with pytest.raises(TransformationError) as err: trans.validate(sgn_calls[0]) - assert ("Sign2CodeTrans cannot be applied to 'SIGN(MAX(ABS(ztmp1), " - "1.e-6_wp), ztmp1) because the type of the argument" + print(err.value) + assert ("Sign2CodeTrans cannot be applied to 'SIGN(thing, " + "ztmp1) because the type of the argument" in str(err.value)) with pytest.raises(TransformationError) as err: trans.validate(sgn_calls[1]) From f2a7258d39a4f7afbccbd598c1aaeff34e2ebd8c Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 4 Sep 2025 09:51:45 +0100 Subject: [PATCH 07/41] Fixed remaining possible coverage --- .../tests/psyir/nodes/intrinsic_call_test.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 03acc37d8b..0fcd4938f6 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -727,6 +727,7 @@ def test__get_first_argument_specified_kind_with_optional_dim(fortran_reader): logical :: c c = ALL(a) b = ALL(a, dim=1) + c = ALL(b, dim=1) end subroutine x """ psyir = fortran_reader.psyir_from_source(code) @@ -740,6 +741,9 @@ def test__get_first_argument_specified_kind_with_optional_dim(fortran_reader): assert dtype.shape[0] == ArrayType.Extent.DEFERRED assert dtype.datatype.intrinsic == ScalarType.Intrinsic.BOOLEAN assert dtype.datatype.precision == ScalarType.Precision.UNDEFINED + dtype = _get_first_argument_specified_kind_with_optional_dim(all_calls[2]) + assert dtype.intrinsic == ScalarType.Intrinsic.BOOLEAN + assert dtype.precision == ScalarType.Precision.UNDEFINED def test_get_real_with_argone_kind(fortran_reader): @@ -793,6 +797,7 @@ def test_get_integer_of_kind_with_optional_dim(fortran_reader): b = COUNT(a) c = COUNT(a, dim=1, kind=8) + b = COUNT(c, dim=1) end subroutine y""" psyir = fortran_reader.psyir_from_source(code) intrs = psyir.walk(IntrinsicCall) @@ -809,6 +814,11 @@ def test_get_integer_of_kind_with_optional_dim(fortran_reader): assert len(res.shape) == 1 assert res.shape[0] == ArrayType.Extent.DEFERRED + res = _get_integer_of_kind_with_optional_dim(intrs[2]) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == ScalarType.Precision.UNDEFINED + def test_findloc_return_type(fortran_reader): """Test the _findloc_return_type helper function.""" @@ -948,6 +958,7 @@ def test_get_first_argument_type_with_optional_kind(fortran_reader): logical*4 :: a logical*8 :: b b = LOGICAL(a, kind=8) + b = LOGICAL(a) end subroutine x""" psyir = fortran_reader.psyir_from_source(code) intrinsics = psyir.walk(IntrinsicCall) @@ -956,6 +967,10 @@ def test_get_first_argument_type_with_optional_kind(fortran_reader): assert isinstance(res, ScalarType) assert res.intrinsic == ScalarType.Intrinsic.BOOLEAN assert res.precision.value == "8" + res = _get_first_argument_type_with_optional_kind(intrinsics[1]) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.BOOLEAN + assert res.precision == 4 def test_get_first_argument_intrinsic_with_optional_kind_and_dim( @@ -1088,6 +1103,7 @@ def test_reduce_return_type(fortran_reader): integer :: y y = REDUCE(x, test) z = REDUCE(x, test, 2) + y = REDUCE(z, test) end subroutine test """ psyir = fortran_reader.psyir_from_source(code) @@ -1115,6 +1131,16 @@ def test_reduce_return_type(fortran_reader): assert len(res.shape) == 1 assert res.shape[0] == ArrayType.Extent.DEFERRED + intrinsic = psyir.walk(ArrayReference)[2] + intrinsic = IntrinsicCall.create( + IntrinsicCall.Intrinsic.REDUCE, + [intrinsic.indices[0].copy(), intrinsic.indices[1].copy()], + ) + res = _reduce_return_type(intrinsic) + assert isinstance(res, ScalarType) + assert res.intrinsic == ScalarType.Intrinsic.INTEGER + assert res.precision == ScalarType.Precision.UNDEFINED + # FIXME Do we need ANINT (also REAL) tests (Reviewer/codecov decision). @pytest.mark.parametrize( From 45fffca46dd79d8180466943cceee19eacd09567 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 4 Sep 2025 10:43:40 +0100 Subject: [PATCH 08/41] Missing coverage line --- src/psyclone/tests/psyir/nodes/intrinsic_call_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 0fcd4938f6..878a4d8d65 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -1103,7 +1103,7 @@ def test_reduce_return_type(fortran_reader): integer :: y y = REDUCE(x, test) z = REDUCE(x, test, 2) - y = REDUCE(z, test) + y = REDUCE(z, test, 2) end subroutine test """ psyir = fortran_reader.psyir_from_source(code) @@ -1134,7 +1134,8 @@ def test_reduce_return_type(fortran_reader): intrinsic = psyir.walk(ArrayReference)[2] intrinsic = IntrinsicCall.create( IntrinsicCall.Intrinsic.REDUCE, - [intrinsic.indices[0].copy(), intrinsic.indices[1].copy()], + [intrinsic.indices[0].copy(), intrinsic.indices[1].copy(), + intrinsic.indices[2].copy()], ) res = _reduce_return_type(intrinsic) assert isinstance(res, ScalarType) From ce1c2829d8b0185f16fda299133cd7a3b77ac1ce Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 4 Sep 2025 13:28:09 +0100 Subject: [PATCH 09/41] Added the ability to change READ access to TYPE_INFO --- src/psyclone/core/access_sequence.py | 39 ++++++++++++++++ .../tests/core/access_sequence_test.py | 45 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/psyclone/core/access_sequence.py b/src/psyclone/core/access_sequence.py index f79294746d..a289b78c86 100644 --- a/src/psyclone/core/access_sequence.py +++ b/src/psyclone/core/access_sequence.py @@ -90,6 +90,16 @@ def change_read_to_write(self): "which does not have 'READ' access.") self._access_type = AccessType.WRITE + def change_read_to_type_info(self): + '''This changes the access mode from READ to TYPE_INFO. + + :raises InternalError: if the variable does not have READ acccess. + ''' + if self._access_type != AccessType.READ: + raise InternalError("Trying to change variable to 'TYPE_INFO' " + "which does not have 'READ' access.") + self._access_type = AccessType.TYPE_INFO + @property def component_indices(self): ''' @@ -310,6 +320,35 @@ def add_access( ''' self.append(AccessInfo(access_type, node, component_indices)) + def change_read_to_type_info(self): + '''This function is used to change a READ into a TYPEINFO. + + :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"'TYPE_INFO' 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_type_info() 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"'TYPE_INFO' but it does not have a 'READ' access.") + read_access.change_read_to_type_info() + def change_read_to_write(self): '''This function is only used when analysing an assignment statement. The LHS has first all variables identified, which will be READ. diff --git a/src/psyclone/tests/core/access_sequence_test.py b/src/psyclone/tests/core/access_sequence_test.py index 16875d847e..d0884489ce 100644 --- a/src/psyclone/tests/core/access_sequence_test.py +++ b/src/psyclone/tests/core/access_sequence_test.py @@ -62,6 +62,15 @@ def test_access_info(): 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_type_info() + assert str(access_info2) == "TYPE_INFO" + assert access_info2.access_type == AccessType.TYPE_INFO + with pytest.raises(InternalError) as err: + access_info2.change_read_to_type_info() + assert ("Trying to change variable to 'TYPE_INFO' which does not have " + "'READ' access." in str(err.value)) # Test setter and getter: component_indices = ComponentIndices([["i"]]) @@ -200,6 +209,42 @@ def test_variable_access_sequence(): assert not accesses.has_data_access() +def test_variable_access_sequence_read_to_type_info(): + ''' + Test the read_to_type_info functionality of AccessSequence + ''' + accesses = AccessSequence(Signature("var_name")) + accesses.add_access(AccessType.INQUIRY, Node(), component_indices=None) + accesses.add_access(AccessType.READ, Node(), component_indices=None) + accesses.change_read_to_type_info() + 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_type_info() + assert ("Trying to change variable 'var_name' to " + "'TYPE_INFO' but it does not have a 'READ' access." + in str(err.value)) + + accesses.add_access(AccessType.WRITE, Node(), component_indices=None) + with pytest.raises(InternalError) as err: + accesses.change_read_to_type_info() + assert ("Variable 'var_name' has a 'WRITE' access. " + "change_read_to_type_info() " + "expects only inquiry accesses and a single 'READ' access." + in str(err.value)) + + accesses = AccessSequence(Signature("var_name")) + accesses.add_access(AccessType.READ, Node(), component_indices=None) + accesses.add_access(AccessType.READ, Node(), component_indices=None) + + with pytest.raises(InternalError) as err: + accesses.change_read_to_type_info() + assert ("Trying to change variable 'var_name' to " + "'TYPE_INFO' but it has more than one 'READ' access." + in str(err.value)) + def test_variable_access_sequence_has_indices(fortran_reader): '''Test that the AccessSequence class handles indices as expected. From d108c89269ee61825e816c2b2d1bf12790a6f358 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 4 Sep 2025 13:28:42 +0100 Subject: [PATCH 10/41] Linting --- src/psyclone/tests/core/access_sequence_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/tests/core/access_sequence_test.py b/src/psyclone/tests/core/access_sequence_test.py index d0884489ce..dbf6a7c18a 100644 --- a/src/psyclone/tests/core/access_sequence_test.py +++ b/src/psyclone/tests/core/access_sequence_test.py @@ -70,7 +70,7 @@ def test_access_info(): with pytest.raises(InternalError) as err: access_info2.change_read_to_type_info() assert ("Trying to change variable to 'TYPE_INFO' which does not have " - "'READ' access." in str(err.value)) + "'READ' access." in str(err.value)) # Test setter and getter: component_indices = ComponentIndices([["i"]]) @@ -245,6 +245,7 @@ def test_variable_access_sequence_read_to_type_info(): "'TYPE_INFO' but it has more than one 'READ' access." in str(err.value)) + def test_variable_access_sequence_has_indices(fortran_reader): '''Test that the AccessSequence class handles indices as expected. From 421f9c2eb682f0821513556e277e2f08aa52d654 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 4 Sep 2025 13:37:45 +0100 Subject: [PATCH 11/41] Start of reference_accesses_changes --- src/psyclone/psyir/nodes/intrinsic_call.py | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 1c553f34ad..59bd12993f 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -86,6 +86,43 @@ ArgDesc = namedtuple("ArgDesc", "min_count max_count types") +def _convert_argument_to_type_info(argument: DataNode, + access_info: VariablesAccessMap) -> None: + """Helper function for the common case where an argument needs to have + a TYPE_INFO access map in access_info instead of a read access. + + :param argument: The argument whose access needs changing. + :param access_info: The access map containing the access. + """ + # TODO + assert False + + +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 TYPE_INFO. + + :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 = node.arguments.reference_accesses() + if kind_index == i: + if isinstance(arg, Reference): + _convert_argument_to_type_info(arg, accesses) + reference_accesses.update(accesses) + + return reference_accesses + + def _get_first_argument_type(node) -> DataType: """Helper function for the common IntrinsicCall case where the return type matches exactly the datatype of the first argument. From 458180e89d4b78fe9d78b9f8b394e97b7394e638 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 5 Sep 2025 10:38:21 +0100 Subject: [PATCH 12/41] read to type_info implemented --- src/psyclone/psyir/nodes/intrinsic_call.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 59bd12993f..76fc828fad 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -94,8 +94,16 @@ def _convert_argument_to_type_info(argument: DataNode, :param argument: The argument whose access needs changing. :param access_info: The access map containing the access. """ - # TODO - assert False + # If the argument isn't a Reference then we don't do anything. + if isinstance(argument, Reference): + sig, _ = argument.get_signature_and_indices() + var_info = access_info[sig] + try: + var_info.change_read_to_type_info() + except InternalError as err: + # The argument here is also used in some other way + # so we do nothing + pass def _reference_accesses_all_reads_with_optional_kind( From c11c8e0925cfd984c0c5a54588366b31428bc708 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Mon, 8 Sep 2025 09:55:31 +0100 Subject: [PATCH 13/41] Moving reference_accesses to its own branch --- src/psyclone/psyir/nodes/intrinsic_call.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 76fc828fad..2615e6a60a 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -45,6 +45,7 @@ from typing import Callable from psyclone.core import AccessType, VariablesAccessMap +from psyclone.errors import InternalError from psyclone.psyir.nodes.operation import BinaryOperation from psyclone.psyir.nodes.call import Call from psyclone.psyir.nodes.datanode import DataNode @@ -100,7 +101,7 @@ def _convert_argument_to_type_info(argument: DataNode, var_info = access_info[sig] try: var_info.change_read_to_type_info() - except InternalError as err: + except InternalError: # The argument here is also used in some other way # so we do nothing pass From 60f12dce696a3edff6c4ed4d67c45ab366950f58 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Tue, 9 Sep 2025 13:15:29 +0100 Subject: [PATCH 14/41] Added support for all read-only reference_accesses --- src/psyclone/core/access_sequence.py | 1 - src/psyclone/psyir/nodes/intrinsic_call.py | 696 +++++++++++++++------ 2 files changed, 495 insertions(+), 202 deletions(-) diff --git a/src/psyclone/core/access_sequence.py b/src/psyclone/core/access_sequence.py index a289b78c86..d24af8a97f 100644 --- a/src/psyclone/core/access_sequence.py +++ b/src/psyclone/core/access_sequence.py @@ -328,7 +328,6 @@ def change_read_to_type_info(self): ''' read_access = None for acc in self: - if acc.access_type == AccessType.READ: if read_access: raise InternalError( diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 2615e6a60a..8a85ba4d00 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -103,7 +103,7 @@ def _convert_argument_to_type_info(argument: DataNode, var_info.change_read_to_type_info() except InternalError: # The argument here is also used in some other way - # so we do nothing + # so we do nothing as the other usage has precedence. pass @@ -123,7 +123,7 @@ def _reference_accesses_all_reads_with_optional_kind( "kind" in node.argument_names else None) reference_accesses = VariablesAccessMap() for i, arg in enumerate(node.arguments): - accesses = node.arguments.reference_accesses() + accesses = arg.reference_accesses() if kind_index == i: if isinstance(arg, Reference): _convert_argument_to_type_info(arg, accesses) @@ -640,7 +640,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO 1590 Complex conversion unsupported. return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ACHAR = IAttr( name="ACHAR", @@ -650,7 +652,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"kind": DataNode}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ACOS = IAttr( name="ACOS", @@ -660,7 +664,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ACOSH = IAttr( name="ACOSH", @@ -670,7 +676,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ADJUSTL = IAttr( name="ADJUSTL", @@ -681,7 +689,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO 2612 This may be more complex if we support character len return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ADJUSTR = IAttr( name="ADJUSTR", @@ -692,7 +702,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO 2612 This may be more complex if we support character len return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) AIMAG = IAttr( name="AIMAG", @@ -703,7 +715,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO #1590 Complex numbers' precision unsupported. return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) AINT = IAttr( name="AINT", @@ -722,7 +736,9 @@ class Intrinsic(IAttr, Enum): ), ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ALL = IAttr( name="ALL", @@ -732,7 +748,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode}, return_type=_get_first_argument_specified_kind_with_optional_dim, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ALLOCATED = IAttr( name="ALLOCATED", @@ -742,7 +760,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry function. ) ANINT = IAttr( name="ANINT", @@ -761,7 +779,9 @@ class Intrinsic(IAttr, Enum): ), ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ANY = IAttr( name="ANY", @@ -771,7 +791,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode}, return_type=_get_first_argument_specified_kind_with_optional_dim, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ASIN = IAttr( name="ASIN", @@ -781,7 +803,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ASINH = IAttr( name="ASINH", @@ -791,7 +815,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ASSOCIATED = IAttr( name="ASSOCIATED", @@ -801,7 +827,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"target": DataNode}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry function ) ATAN = IAttr( name="ATAN", @@ -814,7 +840,9 @@ class Intrinsic(IAttr, Enum): # is the of the second argument, however the standard defines # the type and kind type of both arguments must be the same. return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ATAN2 = IAttr( name="ATAN2", @@ -824,7 +852,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ATANH = IAttr( name="ATANH", @@ -834,7 +864,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ATOMIC_ADD = IAttr( name="ATOMIC_ADD", @@ -844,7 +876,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read Write ) ATOMIC_AND = IAttr( name="ATOMIC_AND", @@ -854,7 +886,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read Write ) ATOMIC_CAS = IAttr( name="ATOMIC_CAS", @@ -864,7 +896,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write Write read read Write ) ATOMIC_DEFINE = IAttr( name="ATOMIC_DEFINE", @@ -874,7 +906,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read Write ) ATOMIC_FETCH_ADD = IAttr( name="ATOMIC_FETCH_ADD", @@ -884,7 +916,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read write write ) ATOMIC_FETCH_AND = IAttr( name="ATOMIC_FETCH_AND", @@ -894,7 +926,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read write write ) ATOMIC_FETCH_OR = IAttr( name="ATOMIC_FETCH_OR", @@ -904,7 +936,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read write write ) ATOMIC_FETCH_XOR = IAttr( name="ATOMIC_FETCH_XOR", @@ -914,7 +946,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read write write ) ATOMIC_OR = IAttr( name="ATOMIC_OR", @@ -924,7 +956,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read Write ) ATOMIC_REF = IAttr( name="ATOMIC_REF", @@ -934,7 +966,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read write ) ATOMIC_XOR = IAttr( name="ATOMIC_XOR", @@ -944,7 +976,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Write read write ) BESSEL_J0 = IAttr( name="BESSEL_J0", @@ -954,7 +986,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_real_with_argone_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_J1 = IAttr( name="BESSEL_J1", @@ -964,7 +998,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_real_with_argone_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_JN = IAttr( name="BESSEL_JN", @@ -974,7 +1010,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 3, DataNode), optional_args={}, return_type=_get_real_with_x_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_Y0 = IAttr( name="BESSEL_Y0", @@ -984,7 +1022,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_real_with_argone_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_Y1 = IAttr( name="BESSEL_Y1", @@ -994,7 +1034,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_real_with_argone_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BESSEL_YN = IAttr( name="BESSEL_YN", @@ -1004,7 +1046,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 3, DataNode), optional_args={}, return_type=_get_real_with_x_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BGE = IAttr( name="BGE", @@ -1014,7 +1058,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BGT = IAttr( name="BGT", @@ -1024,7 +1070,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BIT_SIZE = IAttr( name="BIT_SIZE", @@ -1034,7 +1082,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry function. ) BLE = IAttr( name="BLE", @@ -1044,7 +1092,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BLT = IAttr( name="BLT", @@ -1054,7 +1104,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) BTEST = IAttr( name="BTEST", @@ -1064,7 +1116,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CEILING = IAttr( name="CEILING", @@ -1074,7 +1128,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CHAR = IAttr( name="CHAR", @@ -1084,7 +1140,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"kind": DataNode}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CMPLX = IAttr( name="CMPLX", @@ -1095,7 +1153,9 @@ class Intrinsic(IAttr, Enum): optional_args={"Y": DataNode, "kind": DataNode}, # TODO #1590 Complex numbers unsupported. return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CO_BROADCAST = IAttr( name="CO_BROADCAST", @@ -1105,7 +1165,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 2, DataNode), optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME ReadWrite, READ, Write, Write ) CO_MAX = IAttr( name="CO_MAX", @@ -1117,7 +1177,7 @@ class Intrinsic(IAttr, Enum): "stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME readwrite, read, write, write ) CO_MIN = IAttr( name="CO_MIN", @@ -1129,7 +1189,7 @@ class Intrinsic(IAttr, Enum): "stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME readwrite, read, write, write ) CO_REDUCE = IAttr( name="CO_REDUCE", @@ -1142,6 +1202,7 @@ class Intrinsic(IAttr, Enum): "errmsg": DataNode}, return_type=None, reference_accesses=None, + # FIXME readwrite, inquiry?, read, write, write ) CO_SUM = IAttr( name="CO_SUM", @@ -1153,7 +1214,7 @@ class Intrinsic(IAttr, Enum): "stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME readwrite, read, write, write ) COMMAND_ARGUMENT_COUNT = IAttr( name="COMMAND_ARGUMENT_COUNT", @@ -1163,7 +1224,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(0, 0, None), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME None ) CONJG = IAttr( name="CONJG", @@ -1174,7 +1235,9 @@ class Intrinsic(IAttr, Enum): optional_args={}, # TODO #1590 Complex numbers unsupported. return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) COS = IAttr( name="COS", @@ -1184,7 +1247,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) COSH = IAttr( name="COSH", @@ -1194,7 +1259,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) COSHAPE = IAttr( name="COSHAPE", @@ -1222,7 +1289,7 @@ class Intrinsic(IAttr, Enum): for index in node.arguments[0].datatype.shape ], ), - reference_accesses=None, + reference_accesses=None, # FIXME inquiry, kind ) COUNT = IAttr( name="COUNT", @@ -1232,7 +1299,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_integer_of_kind_with_optional_dim, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) CPU_TIME = IAttr( name="CPU_TIME", @@ -1242,7 +1311,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME write ) CSHIFT = IAttr( name="CSHIFT", @@ -1252,7 +1321,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"dim": DataNode}, return_type=_get_first_argument_type, # FIXME Wait on Sergi reply - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DATE_AND_TIME = IAttr( name="DATE_AND_TIME", @@ -1267,7 +1338,7 @@ class Intrinsic(IAttr, Enum): "values": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME All write arguments ) DBLE = IAttr( name="DBLE", @@ -1277,7 +1348,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=REAL_DOUBLE_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DIGITS = IAttr( name="DIGITS", @@ -1287,7 +1360,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) DIM = IAttr( name="DIM", @@ -1297,7 +1370,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DOT_PRODUCT = IAttr( name="DOT_PRODUCT", @@ -1310,7 +1385,9 @@ class Intrinsic(IAttr, Enum): node.arguments[0].datatype.intrinsic, node.arguments[0].datatype.precision, ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DPROD = IAttr( name="DPROD", @@ -1320,7 +1397,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=REAL8_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DSHIFTL = IAttr( name="DSHIFTL", @@ -1334,7 +1413,9 @@ class Intrinsic(IAttr, Enum): if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) DSHIFTR = IAttr( name="DSHIFTR", @@ -1348,7 +1429,9 @@ class Intrinsic(IAttr, Enum): if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EOSHIFT = IAttr( name="EOSHIFT", @@ -1359,7 +1442,9 @@ class Intrinsic(IAttr, Enum): optional_args={"boundary": DataNode, "dim": DataNode}, return_type=_get_first_argument_type, # FIXME Wait for Sergi reply. - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EPSILON = IAttr( name="EPSILON", @@ -1369,7 +1454,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=None, # FIXME inquiry ) ERF = IAttr( name="ERF", @@ -1379,7 +1464,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_real_with_argone_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ERFC = IAttr( name="ERFC", @@ -1389,7 +1476,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_real_with_argone_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ERFC_SCALED = IAttr( name="ERFC_SCALED", @@ -1399,7 +1488,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_real_with_argone_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EVENT_QUERY = IAttr( name="EVENT_QUERY", @@ -1409,7 +1500,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME read write write ) EXECUTE_COMMAND_LINE = IAttr( name="EXECUTE_COMMAND_LINE", @@ -1424,7 +1515,7 @@ class Intrinsic(IAttr, Enum): "cmdmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME read read write write write ) EXP = IAttr( name="EXP", @@ -1434,7 +1525,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) EXPONENT = IAttr( name="EXPONENT", @@ -1444,7 +1537,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), 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", @@ -1454,7 +1549,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) FAILED_IMAGES = IAttr( name="FAILED_IMAGES", @@ -1474,7 +1569,9 @@ class Intrinsic(IAttr, Enum): ), [ArrayType.Extent.DEFERRED], ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) FINDLOC = IAttr( name="FINDLOC", @@ -1486,7 +1583,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", @@ -1496,7 +1595,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=REAL_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) FLOOR = IAttr( name="FLOOR", @@ -1506,7 +1607,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) FRACTION = IAttr( name="FRACTION", @@ -1516,7 +1619,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) GAMMA = IAttr( name="GAMMA", @@ -1526,7 +1631,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) GET_COMMAND = IAttr( name="GET_COMMAND", @@ -1541,7 +1648,7 @@ class Intrinsic(IAttr, Enum): "errmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME WRITE, WRITE, WRITE ) GET_COMMAND_ARGUMENT = IAttr( name="GET_COMMAND_ARGUMENT", @@ -1553,10 +1660,11 @@ class Intrinsic(IAttr, Enum): "value": DataNode, "length": DataNode, "status": DataNode, + # FIXME THis doesn't take errmsg. "errmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME READ, Write, Write, Write ) GET_ENVIRONMENT_VARIABLE = IAttr( name="GET_ENVIRONMENT_VARIABLE", @@ -1569,10 +1677,11 @@ class Intrinsic(IAttr, Enum): "length": DataNode, "status": DataNode, "trim_name": DataNode, + # FIXME This doesn't take errmsg. "errmsg": DataNode, }, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME read, write, read, write, read ) GET_TEAM = IAttr( name="GET_TEAM", @@ -1583,7 +1692,9 @@ class Intrinsic(IAttr, Enum): optional_args={"level": DataNode}, # Unsupported return type (TEAM_TYPE from ISO_FORTRAN_ENV). return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) HUGE = IAttr( name="HUGE", @@ -1593,7 +1704,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (Reference, Literal)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) HYPOT = IAttr( name="HYPOT", @@ -1603,7 +1716,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IACHAR = IAttr( name="IACHAR", @@ -1613,7 +1728,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IALL = IAttr( name="IALL", @@ -1630,7 +1747,9 @@ class Intrinsic(IAttr, Enum): optional_args={"dim": DataNode, "mask": DataNode}, # There is no kind, but this call will work. return_type=_get_integer_of_kind_with_optional_dim, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IAND = IAttr( name="IAND", @@ -1644,7 +1763,9 @@ class Intrinsic(IAttr, Enum): if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IANY = IAttr( name="IANY", @@ -1661,7 +1782,9 @@ class Intrinsic(IAttr, Enum): optional_args={"dim": DataNode, "mask": DataNode}, # There is no kind, but this call will work. return_type=_get_integer_of_kind_with_optional_dim, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IBCLR = IAttr( name="IBCLR", @@ -1671,7 +1794,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IBITS = IAttr( name="IBITS", @@ -1681,7 +1806,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IBSET = IAttr( name="IBSET", @@ -1691,7 +1818,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ICHAR = IAttr( name="ICHAR", @@ -1701,7 +1830,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IEOR = IAttr( name="IEOR", @@ -1715,7 +1846,9 @@ class Intrinsic(IAttr, Enum): if not isinstance(node.arguments[0], Literal) else node.arguments[1].datatype.copy() ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IMAGE_INDEX = IAttr( name="IMAGE_INDEX", @@ -1725,7 +1858,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 3, (DataNode)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IMAGE_STATUS = IAttr( name="IMAGE_STATUS", @@ -1735,7 +1870,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"team": DataNode}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) INDEX = IAttr( name="INDEX", @@ -1745,7 +1882,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={"back": DataNode, "kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) INT = IAttr( name="INT", @@ -1755,7 +1894,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), 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", @@ -1772,7 +1913,9 @@ class Intrinsic(IAttr, Enum): else node.arguments[1].datatype.precision ), ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) IPARITY = IAttr( name="IPARITY", @@ -1782,7 +1925,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 2, (DataNode)), 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", @@ -1792,7 +1937,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) IS_IOSTAT_END = IAttr( name="IS_IOSTAT_END", @@ -1802,7 +1947,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), 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", @@ -1812,7 +1959,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ISHFT = IAttr( name="ISHFT", @@ -1822,7 +1971,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) ISHFTC = IAttr( name="ISHFTC", @@ -1832,7 +1983,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={"size": DataNode}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) KIND = IAttr( name="KIND", @@ -1842,7 +1995,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) LBOUND = IAttr( name="LBOUND", @@ -1852,7 +2005,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LCOBOUND = IAttr( name="LCOBOUND", @@ -1862,7 +2017,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LEADZ = IAttr( name="LEADZ", @@ -1872,7 +2029,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LEN = IAttr( name="LEN", @@ -1882,7 +2041,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LEN_TRIM = IAttr( name="LEN_TRIM", @@ -1892,7 +2053,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LGE = IAttr( name="LGE", @@ -1902,7 +2065,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LGT = IAttr( name="LGT", @@ -1912,7 +2077,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LLE = IAttr( name="LLE", @@ -1922,7 +2089,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LLT = IAttr( name="LLT", @@ -1932,7 +2101,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, (DataNode)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOG = IAttr( name="LOG", @@ -1942,7 +2113,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOG_GAMMA = IAttr( name="LOG_GAMMA", @@ -1952,7 +2125,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOG10 = IAttr( name="LOG10", @@ -1962,7 +2137,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) LOGICAL = IAttr( name="LOGICAL", @@ -1972,7 +2149,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"kind": DataNode}, return_type=_get_first_argument_type_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MASKL = IAttr( name="MASKL", @@ -1982,7 +2161,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MASKR = IAttr( name="MASKR", @@ -1992,7 +2173,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MATMUL = IAttr( name="MATMUL", @@ -2002,7 +2185,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=_matmul_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MAX = IAttr( name="MAX", @@ -2012,7 +2197,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, None, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MAXEXPONENT = IAttr( name="MAXEXPONENT", @@ -2022,7 +2209,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) MAXLOC = IAttr( name="MAXLOC", @@ -2039,7 +2226,9 @@ class Intrinsic(IAttr, Enum): return_type=( _get_first_argument_intrinsic_with_optional_kind_and_dim ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MAXVAL = IAttr( name="MAXVAL", @@ -2049,7 +2238,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "mask": DataNode}, return_type=_maxval_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MERGE = IAttr( name="MERGE", @@ -2059,7 +2250,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MERGE_BITS = IAttr( name="MERGE_BITS", @@ -2069,7 +2262,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MIN = IAttr( name="MIN", @@ -2079,7 +2274,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, None, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MINEXPONENT = IAttr( name="MINEXPONENT", @@ -2089,7 +2286,10 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), + reference_accesses=None, # FIXME Inquiry function ) MINLOC = IAttr( name="MINLOC", @@ -2106,7 +2306,9 @@ class Intrinsic(IAttr, Enum): return_type=( _get_first_argument_intrinsic_with_optional_kind_and_dim ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MINVAL = IAttr( name="MINVAL", @@ -2116,7 +2318,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "mask": DataNode}, return_type=_maxval_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MOD = IAttr( name="MOD", @@ -2126,7 +2330,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MODULO = IAttr( name="MODULO", @@ -2136,7 +2342,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) MOVE_ALLOC = IAttr( name="MOVE_ALLOC", @@ -2144,9 +2352,10 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(2, 2, DataNode), + # FIXME No stat or errmsg arguments... optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME Readwrite, write ) MVBITS = IAttr( name="MVBITS", @@ -2156,7 +2365,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(5, 5, DataNode), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME read read read write read ) NEAREST = IAttr( name="NEAREST", @@ -2166,17 +2375,20 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NEW_LINE = IAttr( name="NEW_LINE", is_pure=True, is_elemental=True, + # FIXME This is inquiry is_inquiry=False, required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME inquiry ) NINT = IAttr( name="NINT", @@ -2186,7 +2398,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"kind": DataNode}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NORM2 = IAttr( name="NORM2", @@ -2200,7 +2414,9 @@ class Intrinsic(IAttr, Enum): return_type=( _get_first_argument_intrinsic_with_optional_kind_and_dim ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NOT = IAttr( name="NOT", @@ -2213,7 +2429,9 @@ class Intrinsic(IAttr, Enum): ScalarType.Intrinsic.INTEGER, node.arguments[0].datatype.precision ), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) NULL = IAttr( name="NULL", @@ -2224,7 +2442,7 @@ class Intrinsic(IAttr, Enum): optional_args={"mold": DataNode}, # Returns a dissociated pointed - not supported. return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=None, # FIXME type info ) NUM_IMAGES = IAttr( name="NUM_IMAGES", @@ -2234,7 +2452,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(0, 1, DataNode), 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", @@ -2244,7 +2464,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"round": DataNode}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Read, typeinfo, read ) PACK = IAttr( name="PACK", @@ -2259,17 +2479,21 @@ class Intrinsic(IAttr, Enum): node.arguments[0].datatype.precision), [ArrayType.Extent.DEFERRED] ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) PARITY = IAttr( name="PARITY", is_pure=True, is_elemental=False, is_inquiry=False, - required_args=ArgDesc(1, 2, DataNode), - optional_args={}, + required_args=ArgDesc(1, 1, DataNode), + optional_args={"dim": DataNode}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) POPCNT = IAttr( name="POPCNT", @@ -2279,7 +2503,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) POPPAR = IAttr( name="POPPAR", @@ -2289,7 +2515,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) PRECISION = IAttr( name="PRECISION", @@ -2299,7 +2527,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) PRESENT = IAttr( name="PRESENT", @@ -2309,7 +2537,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) PRODUCT = IAttr( name="PRODUCT", @@ -2323,7 +2551,9 @@ class Intrinsic(IAttr, Enum): node, node.arguments[0].datatype.intrinsic ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) RADIX = IAttr( name="RADIX", @@ -2333,7 +2563,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None + reference_accesses=None, # FIXME Inquiry ) RANDOM_INIT = IAttr( name="RANDOM_INIT", @@ -2343,7 +2573,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) RANDOM_NUMBER = IAttr( name="RANDOM_NUMBER", @@ -2353,7 +2585,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME write ) RANDOM_SEED = IAttr( name="RANDOM_SEED", @@ -2363,7 +2595,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(0, 0, Reference), optional_args={"size": DataNode, "put": DataNode, "Get": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME write, read, write ) RANGE = IAttr( name="RANGE", @@ -2373,7 +2605,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME inquiry ) RANK = IAttr( name="RANK", @@ -2383,7 +2615,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None + reference_accesses=None, # FIXME Inquiry ) REAL = IAttr( name="REAL", @@ -2402,7 +2634,9 @@ class Intrinsic(IAttr, Enum): ), ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) REDUCE = IAttr( name="REDUCE", @@ -2414,7 +2648,9 @@ class Intrinsic(IAttr, Enum): "identity": DataNode, "ordered": DataNode}, return_type=_reduce_return_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) REPEAT = IAttr( name="REPEAT", @@ -2424,7 +2660,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=CHARACTER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) RESHAPE = IAttr( name="RESHAPE", @@ -2436,7 +2674,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", @@ -2446,7 +2686,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SAME_TYPE_AS = IAttr( name="SAME_TYPE_AS", @@ -2456,7 +2698,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) SCALE = IAttr( name="SCALE", @@ -2466,7 +2708,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SCAN = IAttr( name="SCAN", @@ -2476,27 +2720,35 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={"back": DataNode, "kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SELECTED_CHAR_KIND = IAttr( name="SELECTED_CHAR_KIND", is_pure=True, is_elemental=False, is_inquiry=False, + # FIXME this should be DataNode? required_args=ArgDesc(1, 1, Reference), 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", is_pure=True, is_elemental=False, is_inquiry=False, + # FIXME this should be DataNode? required_args=ArgDesc(1, 1, Reference), 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", @@ -2506,7 +2758,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(0, 0, Reference), 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", @@ -2516,7 +2770,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SHAPE = IAttr( name="SHAPE", @@ -2536,7 +2792,7 @@ class Intrinsic(IAttr, Enum): Literal(str(len(node.arguments[0].datatype.shape)), INTEGER_TYPE))]) ), - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry, typeinfo ) SHIFTA = IAttr( name="SHIFTA", @@ -2546,7 +2802,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SHIFTL = IAttr( name="SHIFTL", @@ -2556,7 +2814,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SHIFTR = IAttr( name="SHIFTR", @@ -2566,7 +2826,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SIGN = IAttr( name="SIGN", @@ -2576,7 +2838,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SIN = IAttr( name="SIN", @@ -2586,7 +2850,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SINH = IAttr( name="SINH", @@ -2596,7 +2862,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SIZE = IAttr( name="SIZE", @@ -2606,7 +2874,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry, read, type_info ) SPACING = IAttr( name="SPACING", @@ -2616,7 +2884,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=None, # FIXME inquiry ) SPREAD = IAttr( name="SPREAD", @@ -2634,7 +2902,9 @@ class Intrinsic(IAttr, Enum): if isinstance(node.arguments[0].datatype, ArrayType) else [ArrayType.Extent.DEFERRED]) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SQRT = IAttr( name="SQRT", @@ -2646,7 +2916,9 @@ class Intrinsic(IAttr, Enum): # FIXME For reviewer - I put unresolved type because it can return # COMPLEX depending on input. return_type=lambda node: UnresolvedType(), - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) STOPPED_IMAGES = IAttr( name="STOPPED_IMAGES", @@ -2659,7 +2931,9 @@ class Intrinsic(IAttr, Enum): _get_integer_with_optional_kind(node), [ArrayType.Extent.DEFERRED] ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) STORAGE_SIZE = IAttr( name="STORAGE_SIZE", @@ -2669,7 +2943,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) SUM = IAttr( name="SUM", @@ -2685,7 +2959,9 @@ class Intrinsic(IAttr, Enum): node, node.arguments[0].datatype.intrinsic ) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) SYSTEM_CLOCK = IAttr( name="SYSTEM_CLOCK", @@ -2697,7 +2973,7 @@ class Intrinsic(IAttr, Enum): "count_rate": DataNode, "count_max": DataNode}, return_type=None, - reference_accesses=None, + reference_accesses=None, # FIXME write, write, write ) TAN = IAttr( name="TAN", @@ -2707,7 +2983,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TANH = IAttr( name="TANH", @@ -2717,7 +2995,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) # FIXME I'm not sure this exists? TEAM_IMAGE = IAttr( @@ -2742,7 +3022,9 @@ class Intrinsic(IAttr, Enum): "team": DataNode, "dim": DataNode}, return_type=lambda node: UnresolvedType(), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TINY = IAttr( name="TINY", @@ -2752,7 +3034,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (Reference, Literal)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=None, # FIXME Inquiry ) TRAILZ = IAttr( name="TRAILZ", @@ -2762,7 +3044,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TRANSFER = IAttr( name="TRANSFER", @@ -2781,7 +3065,9 @@ class Intrinsic(IAttr, Enum): [ArrayType.Extent.DEFERRED]) ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TRANSPOSE = IAttr( name="TRANSPOSE", @@ -2796,7 +3082,9 @@ class Intrinsic(IAttr, Enum): [node.arguments[0].datatype.shape[1], node.arguments[0].datatype.shape[0]] ), - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) TRIM = IAttr( name="TRIM", @@ -2806,7 +3094,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=CHARACTER_TYPE, - reference_accesses=None + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) UBOUND = IAttr( name="UBOUND", @@ -2816,7 +3106,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=None, # FIXME inquiry, read, type_info ) UCOBOUND = IAttr( name="UCOBOUND", @@ -2826,7 +3116,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, + reference_accesses=None, # FIXME inquiry, read, type_info ) UNPACK = IAttr( name="UNPACK", @@ -2836,7 +3126,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) VERIFY = IAttr( name="VERIFY", @@ -2846,7 +3138,9 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"back": DataNode, "kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, + reference_accesses=( + _reference_accesses_all_reads_with_optional_kind + ), ) def __hash__(self): From 701211677b71db46ef96db66e39ddfaf456ae127 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Tue, 9 Sep 2025 13:22:48 +0100 Subject: [PATCH 15/41] linting --- .../intrinsic_call_reference_accesses_test.py | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py 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..bc11419e84 --- /dev/null +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -0,0 +1,117 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022-2025, 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. + +""" + +import pytest + +from psyclone.core import AccessType +from psyclone.psyir.nodes import ( +# ArrayReference, +# Literal, + Reference, +# Schedule, + Assignment, +) +from psyclone.psyir.nodes.intrinsic_call import ( + IntrinsicCall, + _convert_argument_to_type_info, + _reference_accesses_all_reads_with_optional_kind, +) +from psyclone.psyir.symbols import ( +# ArrayType, + DataSymbol, + INTEGER_TYPE, +# IntrinsicSymbol, +# REAL_TYPE, +# BOOLEAN_TYPE, +# CHARACTER_TYPE, +# ScalarType, +# UnresolvedType, +# NoType +) + + +def test_convert_argument_to_type_info(): + """Test the _convert_argument_to_type_info helper function.""" + # Test that if we supply a Read-only Reference it results in a TYPE_INFO. + symbol = DataSymbol("a", INTEGER_TYPE) + ref = Reference(symbol) + accesses = ref.reference_accesses() + sig, _ = ref.get_signature_and_indices() + assert accesses[sig].is_read_only + _convert_argument_to_type_info(ref, accesses) + assert accesses[sig][0].access_type == AccessType.TYPE_INFO + + # Test if we supply a mixed read/write reference we don't get a TYPE_INFO. + assign = Assignment.create(Reference(symbol), Reference(symbol)) + accesses = assign.reference_accesses() + _convert_argument_to_type_info(assign.lhs, accesses) + sig, _ = assign.lhs.get_signature_and_indices() + for access in accesses[sig]: + assert access.access_type != AccessType.TYPE_INFO + + +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 TYPE_INFO + 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.TYPE_INFO From 9dc0619d35d5a6b242ee47e8d6e906812595872e Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 10 Sep 2025 11:35:06 +0100 Subject: [PATCH 16/41] Finish implementing reference accesses members of each intrinsic --- src/psyclone/psyir/nodes/intrinsic_call.py | 887 ++++++++++++++---- .../intrinsic_call_reference_accesses_test.py | 167 +++- 2 files changed, 882 insertions(+), 172 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 8a85ba4d00..a958d01233 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -87,8 +87,160 @@ ArgDesc = namedtuple("ArgDesc", "min_count max_count types") -def _convert_argument_to_type_info(argument: DataNode, - access_info: VariablesAccessMap) -> None: +def _add_read_argument(argument: DataNode, var_acc_map: VariablesAccessMap): + """Adds a read access for argument into var_acc_map + + :param argument: The argument to add a read access for. + :param var_acc_map: The VariablesAccessMap to add the access into. + """ + # Find all the reference children of the argument (e.g. we could + # have a binary operation argument with multiple, or a Literal + # with none. + for ref in argument.walk(Reference): + sig, all_indices = ref.get_signature_and_indices() + var_acc_map.add_access(sig, AccessType.READ, ref, all_indices) + + +def _add_write_argument(argument: Reference, var_acc_map: VariablesAccessMap): + """Adds a write access for argument into var_acc_map + + :param argument: The argument to add a write access for. + :param var_acc_map: The VariablesAccessMap to add the access into. + """ + sig, all_indices = argument.get_signature_and_indices() + # For Array accesses, these have reads to their indices + for indices in all_indices: + for index in indices: + var_acc_map.update(index.reference_accesses()) + var_acc_map.add_access(sig, AccessType.WRITE, argument, all_indices) + + +def _add_readwrite_argument( + argument: Reference, var_acc_map: VariablesAccessMap +): + """Adds a readwrite access for argument into var_acc_map + + :param argument: The argument to add a readwrite access for. + :param var_acc_map: The VariablesAccessMap to add the access into. + """ + sig, all_indices = argument.get_signature_and_indices() + # For Array accesses, these have reads to their indices + for indices in all_indices: + for index in indices: + var_acc_map.update(index.reference_accesses()) + var_acc_map.add_access(sig, AccessType.READWRITE, argument, all_indices) + + +def _add_typeinfo_argument( + argument: DataNode, var_acc_map: VariablesAccessMap +): + """Adds a type_info access for argument into var_acc_map + + :param argument: The argument to add a type_info access for. + :param var_acc_map: The VariablesAccessMap to add the access into. + """ + # We can get literal as typeinfo expressions, so we skip them. + if not isinstance(argument, Reference): + return + sig, _ = argument.get_signature_and_indices() + var_acc_map.add_access(sig, AccessType.TYPE_INFO, argument) + + +def _add_inquiry_argument( + argument: Reference, var_acc_map: VariablesAccessMap +): + """Adds an inquiry access for argument into var_acc_map + + :param argument: The argument to add a inquiry access for. + :param var_acc_map: The VariablesAccessMap to add the access into. + """ + # FIXME For reviewer - can we have a non-Reference inquiry argument? + sig, _ = argument.get_signature_and_indices() + var_acc_map.add_access(sig, AccessType.INQUIRY, argument) + + +def _compute_reference_accesses( + node, + read_indices: list[int] = None, + write_indices: list[int] = None, + readwrite_indices: list[int] = None, + type_info_indices: list[int] = None, + inquiry_indices: list[int] = None, + read_named_args: list[str] = None, + write_named_args: list[str] = None, + readwrite_named_args: list[str] = None, + type_info_named_args: list[str] = None, + inquiry_named_args: list[str] = None, +) -> VariablesAccessMap: + """General helper function for creating the reference_accesses for a + general IntrinsicCall. + + :param node: the IntrinsicCall whose reference_accesses to compute. + :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` + :param read_indices: the argument indices of each read access. + :param write_indices: the argument indices of each write access. + :param type_info_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 type_info_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 in read_indices: + arg = node.arguments[ind] + _add_read_argument(arg, reference_accesses) + for ind in write_indices: + arg = node.arguments[ind] + _add_write_argument(arg, reference_accesses) + for ind in readwrite_indices: + arg = node.arguments[ind] + _add_readwrite_argument(arg, reference_accesses) + for ind in type_info_indices: + arg = node.arguments[ind] + _add_typeinfo_argument(arg, reference_accesses) + for ind in inquiry_indices: + arg = node.arguments[ind] + _add_inquiry_argument(arg, reference_accesses) + # For each named argument provided, we check if they are defined + # for the given intrinsicCall as they are optional. + for name in read_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_read_argument(arg, reference_accesses) + for name in write_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_write_argument(arg, reference_accesses) + for name in type_info_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_typeinfo_argument(arg, reference_accesses) + for name in inquiry_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_inquiry_argument(arg, reference_accesses) + for name in readwrite_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_readwrite_argument(arg, reference_accesses) + + return reference_accesses + + +def _convert_argument_to_type_info( + argument: DataNode, access_info: VariablesAccessMap +) -> None: """Helper function for the common case where an argument needs to have a TYPE_INFO access map in access_info instead of a read access. @@ -108,7 +260,7 @@ def _convert_argument_to_type_info(argument: DataNode, def _reference_accesses_all_reads_with_optional_kind( - node + node, ) -> VariablesAccessMap: """Helper function for the common IntrinsicCall case where all arguments are read only, with the exception of an optional kind named @@ -119,8 +271,11 @@ def _reference_accesses_all_reads_with_optional_kind( :returns: the reference accesses of node. """ - kind_index = (node.argument_names.index("kind") if - "kind" in node.argument_names else None) + 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() @@ -209,8 +364,8 @@ def _get_first_argument_intrinsic_with_optional_kind_and_dim(node) -> DataType: def _get_first_argument_specified_kind_with_optional_dim( - node, intrinsic: ScalarType.Intrinsic = ScalarType.Intrinsic.BOOLEAN - ) -> DataType: + node, intrinsic: ScalarType.Intrinsic = ScalarType.Intrinsic.BOOLEAN +) -> DataType: """Helper function for the common IntrinsicCall case where the return type is a Scalar with the kind of the first argument, unless an option dim parameter is given in which case an array with @@ -223,9 +378,7 @@ def _get_first_argument_specified_kind_with_optional_dim( :returns: the computed datatype for the IntrinsicCall. """ - dtype = ScalarType( - intrinsic, node.arguments[0].datatype.precision - ) + dtype = ScalarType(intrinsic, node.arguments[0].datatype.precision) if "dim" not in node.argument_names: return dtype else: @@ -469,8 +622,7 @@ def _matmul_return_type(node) -> DataType: # Create a temporary BinaryOperation to use get_result_scalar_type arg1 = Reference(DataSymbol("a", stype1)) arg2 = Reference(DataSymbol("b", stype2)) - binop = BinaryOperation.create(BinaryOperation.Operator.MUL, - arg1, arg2) + binop = BinaryOperation.create(BinaryOperation.Operator.MUL, arg1, arg2) # TODO - make this a public method? stype = binop._get_result_scalar_type([stype1, stype2]) # a11 a12 x b1 = a11*b1 + a12*b2 @@ -481,31 +633,31 @@ def _matmul_return_type(node) -> DataType: if len(shape1) == 1: extent = IntrinsicCall.create( IntrinsicCall.Intrinsic.SIZE, - [node.arguments[1].copy(), - ("dim", Literal("1", INTEGER_TYPE))]) + [node.arguments[1].copy(), ("dim", Literal("1", INTEGER_TYPE))], + ) shape = [extent] elif len(shape2) == 1: extent = IntrinsicCall.create( IntrinsicCall.Intrinsic.SIZE, - [node.arguments[0].copy(), - ("dim", Literal("1", INTEGER_TYPE))]) + [node.arguments[0].copy(), ("dim", Literal("1", INTEGER_TYPE))], + ) shape = [extent] else: # matrix-matrix. Result is size(arg0, 1) x size(arg1, 2) extent1 = IntrinsicCall.create( IntrinsicCall.Intrinsic.SIZE, - [node.arguments[0].copy(), - ("dim", Literal("1", INTEGER_TYPE))]) + [node.arguments[0].copy(), ("dim", Literal("1", INTEGER_TYPE))], + ) extent2 = IntrinsicCall.create( IntrinsicCall.Intrinsic.SIZE, - [node.arguments[1].copy(), - ("dim", Literal("2", INTEGER_TYPE))]) + [node.arguments[1].copy(), ("dim", Literal("2", INTEGER_TYPE))], + ) shape = [extent1, extent2] return ArrayType(stype, shape) def _maxval_return_type(node) -> DataType: - """ Helper function for the MAXVAL (and similar) intrinsic return + """Helper function for the MAXVAL (and similar) intrinsic return types. :param node: The IntrinsicCall whose return type to compute. @@ -513,10 +665,14 @@ def _maxval_return_type(node) -> DataType: :returns: the computed datatype for the IntrinsicCall. """ - dtype = ScalarType(node.arguments[0].datatype.intrinsic, - node.arguments[0].datatype.precision) - if ("dim" not in node.argument_names - or len(node.arguments[0].datatype.shape) == 1): + dtype = ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision, + ) + if ( + "dim" not in node.argument_names + or len(node.arguments[0].datatype.shape) == 1 + ): return dtype # We have a dimension specified. We don't know the resultant shape # in any detail as its dependent on the value of dim @@ -528,7 +684,7 @@ def _maxval_return_type(node) -> DataType: def _reduce_return_type(node) -> DataType: - """ Helper function for the REDUCE intrinsic return type. + """Helper function for the REDUCE intrinsic return type. :param node: The IntrinsicCall whose return type to compute. :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` @@ -536,10 +692,11 @@ def _reduce_return_type(node) -> DataType: :returns: the computed datatype for the IntrinsicCall. """ # Check if we have dim - have_dim = (len(node.arguments) > 2 and - node.argument_names[2] is None) - dtype = ScalarType(node.arguments[0].datatype.intrinsic, - node.arguments[0].datatype.precision) + have_dim = len(node.arguments) > 2 and node.argument_names[2] is None + dtype = ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision, + ) if not have_dim: return dtype if len(node.arguments[0].datatype.shape) == 1: @@ -607,7 +764,21 @@ class Intrinsic(IAttr, Enum): "errmsg": Reference, }, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + # All the arguments before a keyword + # argument are write indices. + write_indices=list( + range( + len(node.arguments) + - node.argument_names[::-1].index(None) + ) + ), + read_named_args=["mold", "source"], + write_named_args=["stat", "errmsg"], + ) + ), ) DEALLOCATE = IAttr( name="DEALLOCATE", @@ -617,7 +788,20 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, None, Reference), optional_args={"stat": Reference}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + # All the arguments before a keyword + # argument are write indices. + write_indices=list( + range( + len(node.arguments) + - node.argument_names[::-1].index(None) + ) + ), + write_named_args=["stat"], + ) + ), ) NULLIFY = IAttr( name="NULLIFY", @@ -627,7 +811,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, None, Reference), optional_args={}, return_type=None, - reference_accesses=None, + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_indices=list(range(len(node.arguments))), + ) + ), ) # Fortran Intrinsics (from Fortran 2018 standard table 16.1) @@ -760,7 +949,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, # FIXME Inquiry function. + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) ANINT = IAttr( name="ANINT", @@ -827,7 +1021,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"target": DataNode}, return_type=BOOLEAN_TYPE, - reference_accesses=None, # FIXME Inquiry function + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) ATAN = IAttr( name="ATAN", @@ -876,7 +1075,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read Write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_AND = IAttr( name="ATOMIC_AND", @@ -886,17 +1092,32 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read Write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_CAS = IAttr( name="ATOMIC_CAS", is_pure=True, is_elemental=True, is_inquiry=False, - required_args=ArgDesc(2, 2, DataNode), + required_args=ArgDesc(4, 4, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write Write read read Write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[2, 3], + write_indices=[1], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_DEFINE = IAttr( name="ATOMIC_DEFINE", @@ -906,7 +1127,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read Write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_FETCH_ADD = IAttr( name="ATOMIC_FETCH_ADD", @@ -916,7 +1144,15 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read write write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + write_indices=[2], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_FETCH_AND = IAttr( name="ATOMIC_FETCH_AND", @@ -926,7 +1162,15 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read write write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + write_indices=[2], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_FETCH_OR = IAttr( name="ATOMIC_FETCH_OR", @@ -936,7 +1180,15 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read write write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + write_indices=[2], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_FETCH_XOR = IAttr( name="ATOMIC_FETCH_XOR", @@ -946,7 +1198,15 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(3, 3, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read write write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + write_indices=[2], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_OR = IAttr( name="ATOMIC_OR", @@ -956,7 +1216,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read Write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_REF = IAttr( name="ATOMIC_REF", @@ -966,7 +1233,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) ATOMIC_XOR = IAttr( name="ATOMIC_XOR", @@ -976,7 +1250,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME Write read write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[1], + readwrite_indices=[0], + write_named_args=["stat"], + ) + ), ) BESSEL_J0 = IAttr( name="BESSEL_J0", @@ -1082,7 +1363,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME Inquiry function. + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) BLE = IAttr( name="BLE", @@ -1165,7 +1451,18 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 2, DataNode), optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, # FIXME ReadWrite, READ, Write, Write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + # If there are 2 non-optional args then the second is a + # read. + read_indices=( + [] if node.argument_names.count(None) == 1 else [1], + ), + readwrite_indices=[0], + write_names_args=["stat", "errmsg"], + ) + ), ) CO_MAX = IAttr( name="CO_MAX", @@ -1173,11 +1470,20 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(1, 1, DataNode), - optional_args={"result_image": DataNode, - "stat": DataNode, - "errmsg": DataNode}, + optional_args={ + "result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode, + }, return_type=None, - reference_accesses=None, # FIXME readwrite, read, write, write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_indices=[0], + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) CO_MIN = IAttr( name="CO_MIN", @@ -1185,11 +1491,20 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(1, 1, DataNode), - optional_args={"result_image": DataNode, - "stat": DataNode, - "errmsg": DataNode}, + optional_args={ + "result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode, + }, return_type=None, - reference_accesses=None, # FIXME readwrite, read, write, write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_indices=[0], + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) CO_REDUCE = IAttr( name="CO_REDUCE", @@ -1197,12 +1512,25 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(1, 2, DataNode), - optional_args={"result_image": DataNode, - "stat": DataNode, - "errmsg": DataNode}, + optional_args={ + "result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode, + }, return_type=None, - reference_accesses=None, - # FIXME readwrite, inquiry?, read, write, write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_indices=[0], + # If there are 2 non-optional args then the second is a + # read. + inquiry_indices=( + [] if node.argument_names.count(None) == 1 else [1], + ), + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) CO_SUM = IAttr( name="CO_SUM", @@ -1210,11 +1538,20 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(1, 1, DataNode), - optional_args={"result_image": DataNode, - "stat": DataNode, - "errmsg": DataNode}, + optional_args={ + "result_image": DataNode, + "stat": DataNode, + "errmsg": DataNode, + }, return_type=None, - reference_accesses=None, # FIXME readwrite, read, write, write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_indices=[0], + read_named_args=["result_image"], + write_named_args=["stat", "errmsg"], + ) + ), ) COMMAND_ARGUMENT_COUNT = IAttr( name="COMMAND_ARGUMENT_COUNT", @@ -1224,7 +1561,7 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(0, 0, None), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME None + reference_accesses=lambda node: VariablesAccessMap(), ) CONJG = IAttr( name="CONJG", @@ -1289,7 +1626,13 @@ class Intrinsic(IAttr, Enum): for index in node.arguments[0].datatype.shape ], ), - reference_accesses=None, # FIXME inquiry, kind + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + type_info_named_arguments=["kind"], + ) + ), ) COUNT = IAttr( name="COUNT", @@ -1311,7 +1654,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=None, - reference_accesses=None, # FIXME write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_indices=[0], + ) + ), ) CSHIFT = IAttr( name="CSHIFT", @@ -1338,7 +1686,12 @@ class Intrinsic(IAttr, Enum): "values": DataNode, }, return_type=None, - reference_accesses=None, # FIXME All write arguments + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_indices=["date", "time", "zone", "values"], + ) + ), ) DBLE = IAttr( name="DBLE", @@ -1360,7 +1713,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) DIM = IAttr( name="DIM", @@ -1454,7 +1812,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, # FIXME inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) ERF = IAttr( name="ERF", @@ -1500,14 +1863,21 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode}, return_type=None, - reference_accesses=None, # FIXME read write write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[0], + write_indices=[0], + write_named_args=["stat"], + ) + ), ) EXECUTE_COMMAND_LINE = IAttr( name="EXECUTE_COMMAND_LINE", is_pure=False, is_elemental=False, is_inquiry=False, - required_args=ArgDesc(2, 2, DataNode), + required_args=ArgDesc(1, 1, DataNode), optional_args={ "wait": DataNode, "exitstat": DataNode, @@ -1515,7 +1885,14 @@ class Intrinsic(IAttr, Enum): "cmdmsg": DataNode, }, return_type=None, - reference_accesses=None, # FIXME read read write write write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[0], + read_named_args=["wait"], + write_named_args=["exitstat", "cmdstat", "cmdmsg"], + ) + ), ) EXP = IAttr( name="EXP", @@ -1549,7 +1926,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0, 1], + ) + ), ) FAILED_IMAGES = IAttr( name="FAILED_IMAGES", @@ -1579,9 +1961,11 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(2, 3, DataNode), - optional_args={"mask": DataNode, - "kind": DataNode, - "back": DataNode}, + optional_args={ + "mask": DataNode, + "kind": DataNode, + "back": DataNode, + }, return_type=_findloc_return_type, reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -1648,7 +2032,13 @@ class Intrinsic(IAttr, Enum): "errmsg": DataNode, }, return_type=None, - reference_accesses=None, # FIXME WRITE, WRITE, WRITE + 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", @@ -1660,11 +2050,17 @@ class Intrinsic(IAttr, Enum): "value": DataNode, "length": DataNode, "status": DataNode, - # FIXME THis doesn't take errmsg. "errmsg": DataNode, }, return_type=None, - reference_accesses=None, # FIXME READ, Write, Write, Write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[0], + write_named_args=["value", "length", "status"], + readwrite_named_Args=["errmsg"], + ) + ), ) GET_ENVIRONMENT_VARIABLE = IAttr( name="GET_ENVIRONMENT_VARIABLE", @@ -1677,11 +2073,18 @@ class Intrinsic(IAttr, Enum): "length": DataNode, "status": DataNode, "trim_name": DataNode, - # FIXME This doesn't take errmsg. "errmsg": DataNode, }, return_type=None, - reference_accesses=None, # FIXME read, write, read, write, read + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[0], + write_named_args=["value", "length", "status"], + read_named_args=["trim_name"], + readwrite_named_Args=["errmsg"], + ) + ), ) GET_TEAM = IAttr( name="GET_TEAM", @@ -1937,7 +2340,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) IS_IOSTAT_END = IAttr( name="IS_IOSTAT_END", @@ -1995,7 +2403,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) LBOUND = IAttr( name="LBOUND", @@ -2209,7 +2622,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) MAXLOC = IAttr( name="MAXLOC", @@ -2286,10 +2704,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=( - _reference_accesses_all_reads_with_optional_kind + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) ), - reference_accesses=None, # FIXME Inquiry function ) MINLOC = IAttr( name="MINLOC", @@ -2352,10 +2772,17 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(2, 2, DataNode), - # FIXME No stat or errmsg arguments... optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, - reference_accesses=None, # FIXME Readwrite, write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + readwrite_indices=[0], + write_indices=[1], + write_named_args=["stat"], + readwrite_named_args=["errmsg"], + ) + ), ) MVBITS = IAttr( name="MVBITS", @@ -2365,7 +2792,13 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(5, 5, DataNode), optional_args={}, return_type=None, - reference_accesses=None, # FIXME read read read write read + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[0, 1, 2, 4], + write_indices=[3], + ) + ), ) NEAREST = IAttr( name="NEAREST", @@ -2383,12 +2816,16 @@ class Intrinsic(IAttr, Enum): name="NEW_LINE", is_pure=True, is_elemental=True, - # FIXME This is inquiry - is_inquiry=False, + is_inquiry=True, required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=CHARACTER_TYPE, - reference_accesses=None, # FIXME inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) NINT = IAttr( name="NINT", @@ -2427,7 +2864,7 @@ class Intrinsic(IAttr, Enum): optional_args={}, return_type=lambda node: ScalarType( ScalarType.Intrinsic.INTEGER, - node.arguments[0].datatype.precision + node.arguments[0].datatype.precision, ), reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -2442,7 +2879,12 @@ class Intrinsic(IAttr, Enum): optional_args={"mold": DataNode}, # Returns a dissociated pointed - not supported. return_type=lambda node: UnresolvedType(), - reference_accesses=None, # FIXME type info + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + type_info_named_args=["mold"], + ) + ), ) NUM_IMAGES = IAttr( name="NUM_IMAGES", @@ -2464,7 +2906,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"round": DataNode}, return_type=BOOLEAN_TYPE, - reference_accesses=None, # FIXME Read, typeinfo, read + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_indices=[0], + type_info_indices=[1], + read_named_args=["round"], + ) + ), ) PACK = IAttr( name="PACK", @@ -2476,8 +2925,9 @@ class Intrinsic(IAttr, Enum): return_type=lambda node: ArrayType( ScalarType( node.arguments[0].datatype.intrinsic, - node.arguments[0].datatype.precision), - [ArrayType.Extent.DEFERRED] + node.arguments[0].datatype.precision, + ), + [ArrayType.Extent.DEFERRED], ), reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -2527,7 +2977,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) PRESENT = IAttr( name="PRESENT", @@ -2537,7 +2992,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) PRODUCT = IAttr( name="PRODUCT", @@ -2563,7 +3023,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) RANDOM_INIT = IAttr( name="RANDOM_INIT", @@ -2585,7 +3050,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={}, return_type=None, - reference_accesses=None, # FIXME write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_indices=[0], + ) + ), ) RANDOM_SEED = IAttr( name="RANDOM_SEED", @@ -2593,9 +3063,15 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(0, 0, Reference), - optional_args={"size": DataNode, "put": DataNode, "Get": DataNode}, + optional_args={"size": DataNode, "put": DataNode, "get": DataNode}, return_type=None, - reference_accesses=None, # FIXME write, read, write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + read_named_args=["put"], + write_named_args=["size", "get"], + ) + ), ) RANGE = IAttr( name="RANGE", @@ -2605,7 +3081,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) RANK = IAttr( name="RANK", @@ -2615,7 +3096,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={}, return_type=INTEGER_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) REAL = IAttr( name="REAL", @@ -2644,9 +3130,11 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(2, 3, DataNode), - optional_args={"mask": DataNode, - "identity": DataNode, - "ordered": DataNode}, + optional_args={ + "mask": DataNode, + "identity": DataNode, + "ordered": DataNode, + }, return_type=_reduce_return_type, reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -2698,7 +3186,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, Reference), optional_args={}, return_type=BOOLEAN_TYPE, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) SCALE = IAttr( name="SCALE", @@ -2729,8 +3222,7 @@ class Intrinsic(IAttr, Enum): is_pure=True, is_elemental=False, is_inquiry=False, - # FIXME this should be DataNode? - required_args=ArgDesc(1, 1, Reference), + required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, reference_accesses=( @@ -2742,8 +3234,7 @@ class Intrinsic(IAttr, Enum): is_pure=True, is_elemental=False, is_inquiry=False, - # FIXME this should be DataNode? - required_args=ArgDesc(1, 1, Reference), + required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=INTEGER_TYPE, reference_accesses=( @@ -2782,17 +3273,35 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, Reference), optional_args={"kind": DataNode}, return_type=lambda node: ( - ArrayType(ScalarType( - ScalarType.Intrinsic.INTEGER, - (ScalarType.Precision.UNDEFINED if "kind" not in - node.argument_names else - node.arguments[node.argument_names.index("kind")])), - [ArrayType.ArrayBounds( - Literal("1", INTEGER_TYPE), - Literal(str(len(node.arguments[0].datatype.shape)), - INTEGER_TYPE))]) + ArrayType( + ScalarType( + ScalarType.Intrinsic.INTEGER, + ( + ScalarType.Precision.UNDEFINED + if "kind" not in node.argument_names + else node.arguments[ + node.argument_names.index("kind") + ] + ), + ), + [ + ArrayType.ArrayBounds( + Literal("1", INTEGER_TYPE), + Literal( + str(len(node.arguments[0].datatype.shape)), + INTEGER_TYPE, + ), + ) + ], + ) + ), + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + typeinfo_named_args=["kind"], + ) ), - reference_accesses=None, # FIXME Inquiry, typeinfo ) SHIFTA = IAttr( name="SHIFTA", @@ -2874,7 +3383,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, # FIXME Inquiry, read, type_info + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + read_named_args=["dim"], + typeinfo_named_args=["kind"], + ) + ), ) SPACING = IAttr( name="SPACING", @@ -2884,7 +3400,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, # FIXME inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) SPREAD = IAttr( name="SPREAD", @@ -2896,11 +3417,14 @@ class Intrinsic(IAttr, Enum): return_type=lambda node: ArrayType( ScalarType( node.arguments[0].datatype.intrinsic, - node.arguments[0].datatype.precision), - ([ArrayType.Extent.DEFERRED] * - (len(node.arguments[0].datatype.shape) + 1) - if isinstance(node.arguments[0].datatype, ArrayType) else - [ArrayType.Extent.DEFERRED]) + node.arguments[0].datatype.precision, + ), + ( + [ArrayType.Extent.DEFERRED] + * (len(node.arguments[0].datatype.shape) + 1) + if isinstance(node.arguments[0].datatype, ArrayType) + else [ArrayType.Extent.DEFERRED] + ), ), reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -2929,7 +3453,7 @@ class Intrinsic(IAttr, Enum): optional_args={"team": DataNode, "kind": DataNode}, return_type=lambda node: ArrayType( _get_integer_with_optional_kind(node), - [ArrayType.Extent.DEFERRED] + [ArrayType.Extent.DEFERRED], ), reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -2943,7 +3467,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"kind": DataNode}, return_type=_get_integer_with_optional_kind, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) SUM = IAttr( name="SUM", @@ -2951,7 +3480,7 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, # FIXME Think this is wrong again - 2nd argument can be non-named - # dim? + # dim not named? Is my understanding. required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "mask": DataNode}, return_type=lambda node: ( @@ -2969,11 +3498,22 @@ class Intrinsic(IAttr, Enum): is_elemental=False, is_inquiry=False, required_args=ArgDesc(0, 0, DataNode), - optional_args={"count": DataNode, - "count_rate": DataNode, - "count_max": DataNode}, + optional_args={ + "count": DataNode, + "count_rate": DataNode, + "count_max": DataNode, + }, return_type=None, - reference_accesses=None, # FIXME write, write, write + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + write_named_args=[ + "count", + "count_rate", + "count_max", + ], + ) + ), ) TAN = IAttr( name="TAN", @@ -3018,9 +3558,11 @@ class Intrinsic(IAttr, Enum): # FIXME Again not sure this is correct. Have used unresolved # type for the return value - can improve it if wanted. required_args=ArgDesc(0, 0, DataNode), - optional_args={"coarray": DataNode, - "team": DataNode, - "dim": DataNode}, + optional_args={ + "coarray": DataNode, + "team": DataNode, + "dim": DataNode, + }, return_type=lambda node: UnresolvedType(), reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -3034,7 +3576,12 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (Reference, Literal)), optional_args={}, return_type=_get_first_argument_type, - reference_accesses=None, # FIXME Inquiry + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + ) + ), ) TRAILZ = IAttr( name="TRAILZ", @@ -3056,14 +3603,18 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(2, 2, DataNode), optional_args={"size": DataNode}, return_type=lambda node: ( - node.arguments[1].datatype if - ("size" not in node.argument_names and - not isinstance(node.arguments[1].datatype, ArrayType)) + node.arguments[1].datatype + if ( + "size" not in node.argument_names + and not isinstance(node.arguments[1].datatype, ArrayType) + ) else ArrayType( - ScalarType(node.arguments[1].datatype.intrinsic, - node.arguments[1].datatype.precision), - [ArrayType.Extent.DEFERRED]) - + ScalarType( + node.arguments[1].datatype.intrinsic, + node.arguments[1].datatype.precision, + ), + [ArrayType.Extent.DEFERRED], + ) ), reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -3076,11 +3627,15 @@ class Intrinsic(IAttr, Enum): is_inquiry=False, required_args=ArgDesc(1, 1, DataNode), optional_args={}, - return_type=lambda node: ArrayType(ScalarType( - node.arguments[0].datatype.intrinsic, - node.arguments[0].datatype.precision), - [node.arguments[0].datatype.shape[1], - node.arguments[0].datatype.shape[0]] + return_type=lambda node: ArrayType( + ScalarType( + node.arguments[0].datatype.intrinsic, + node.arguments[0].datatype.precision, + ), + [ + node.arguments[0].datatype.shape[1], + node.arguments[0].datatype.shape[0], + ], ), reference_accesses=( _reference_accesses_all_reads_with_optional_kind @@ -3106,7 +3661,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, # FIXME inquiry, read, type_info + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + read_named_args=["dim"], + type_info_named_args=["kind"], + ) + ), ) UCOBOUND = IAttr( name="UCOBOUND", @@ -3116,7 +3678,14 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, DataNode), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=None, # FIXME inquiry, read, type_info + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + read_named_args=["dim"], + type_info_named_args=["kind"], + ) + ), ) UNPACK = IAttr( name="UNPACK", 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 index bc11419e84..3aa7e12c08 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -42,35 +42,176 @@ """ -import pytest +# import pytest -from psyclone.core import AccessType +from psyclone.core import AccessType, VariablesAccessMap from psyclone.psyir.nodes import ( -# ArrayReference, -# Literal, + ArrayReference, + Literal, Reference, -# Schedule, Assignment, + BinaryOperation ) from psyclone.psyir.nodes.intrinsic_call import ( IntrinsicCall, _convert_argument_to_type_info, _reference_accesses_all_reads_with_optional_kind, + _add_read_argument, + _add_write_argument, + _add_readwrite_argument, + _add_typeinfo_argument, + _add_inquiry_argument, ) from psyclone.psyir.symbols import ( -# ArrayType, + ArrayType, DataSymbol, INTEGER_TYPE, -# IntrinsicSymbol, -# REAL_TYPE, -# BOOLEAN_TYPE, -# CHARACTER_TYPE, -# ScalarType, -# UnresolvedType, -# NoType + # IntrinsicSymbol, + # REAL_TYPE, + # BOOLEAN_TYPE, + # CHARACTER_TYPE, + # ScalarType, + # UnresolvedType, + # NoType ) +def test_add_read_argument(): + """ Test the _add_read_argument helper function.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_read_argument(ref, vam) + + 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_read_argument(lit, vam) + 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_read_argument(binop, vam) + 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_read_argument(ref, vam) + 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 + +def test_add_write_argument(): + """ Test the _add_write_argument helper function.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_write_argument(ref, vam) + + 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_write_argument(aref, vam) + 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 + + +def test_add_readwrite_argument(): + """ Test the _add_readwrite_argument helper function.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_readwrite_argument(ref, vam) + + 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_readwrite_argument(aref, vam) + 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_typeinfo_argument(): + """ Test the _add_typeinfo_argument helper function.""" + # Test we get expected behaviour for a Reference input. + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_typeinfo_argument(ref, vam) + + sig, _ = ref.get_signature_and_indices() + assert len(vam) == 1 + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.TYPE_INFO + + # Test we skip for a Literal + vam = VariablesAccessMap() + lit = Literal("1", INTEGER_TYPE) + _add_typeinfo_argument(lit, vam) + assert len(vam) == 0 + + +def test_add_inquiry_argument(): + """ Test the _add_inquiry_argument helper function.""" + symbol = DataSymbol("a", INTEGER_TYPE) + vam = VariablesAccessMap() + ref = Reference(symbol) + _add_inquiry_argument(ref, vam) + + sig, _ = ref.get_signature_and_indices() + assert len(vam) == 1 + assert len(vam[sig]) == 1 + assert vam[sig][0].access_type == AccessType.INQUIRY + + +# FIXME Test _compute_reference_accesses def test_convert_argument_to_type_info(): """Test the _convert_argument_to_type_info helper function.""" # Test that if we supply a Read-only Reference it results in a TYPE_INFO. From ac424280896b17de38ed9559f5cb8fb2ef310ebb Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 10 Sep 2025 11:35:50 +0100 Subject: [PATCH 17/41] linting --- .../psyir/nodes/intrinsic_call_reference_accesses_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 3aa7e12c08..0593677563 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -128,6 +128,7 @@ def test_add_read_argument(): assert len(vam[sig]) == 1 assert vam[sig][0].access_type == AccessType.READ + def test_add_write_argument(): """ Test the _add_write_argument helper function.""" # Test we get expected behaviour for a Reference input. @@ -209,7 +210,7 @@ def test_add_inquiry_argument(): assert len(vam) == 1 assert len(vam[sig]) == 1 assert vam[sig][0].access_type == AccessType.INQUIRY - + # FIXME Test _compute_reference_accesses def test_convert_argument_to_type_info(): From 144ef08f62326df212063f418954c1c31c07bc24 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 10 Sep 2025 13:32:44 +0100 Subject: [PATCH 18/41] Fix failing test --- src/psyclone/tests/psyir/nodes/intrinsic_call_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 878a4d8d65..781c0b41fd 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -918,7 +918,7 @@ def test_iparity_return_type(fortran_reader): intrinsic = psyir.walk(ArrayReference)[0] intrinsic = IntrinsicCall.create( IntrinsicCall.Intrinsic.PARITY, - [intrinsic.indices[0].copy(), Reference(k_sym)], + [intrinsic.indices[0].copy(), ("dim", Reference(k_sym))], ) res = _iparity_return_type(intrinsic) assert isinstance(res, ArrayType) From 47f46e9a0333928ab8b43992b04a5bf11190ac72 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 10 Sep 2025 14:24:55 +0100 Subject: [PATCH 19/41] Added test for compute_reference_accesses --- .../intrinsic_call_reference_accesses_test.py | 94 +++++++++++++++++-- 1 file changed, 86 insertions(+), 8 deletions(-) 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 index 0593677563..65ff5d4990 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -50,7 +50,8 @@ Literal, Reference, Assignment, - BinaryOperation + BinaryOperation, + Call ) from psyclone.psyir.nodes.intrinsic_call import ( IntrinsicCall, @@ -61,18 +62,13 @@ _add_readwrite_argument, _add_typeinfo_argument, _add_inquiry_argument, + _compute_reference_accesses, ) from psyclone.psyir.symbols import ( ArrayType, DataSymbol, INTEGER_TYPE, - # IntrinsicSymbol, - # REAL_TYPE, - # BOOLEAN_TYPE, - # CHARACTER_TYPE, - # ScalarType, - # UnresolvedType, - # NoType + RoutineSymbol ) @@ -213,6 +209,88 @@ def test_add_inquiry_argument(): # FIXME Test _compute_reference_accesses +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), + ("type_info", i_ref), + ("inquiry", j_ref), + ] + ) + varaccesses = _compute_reference_accesses( + call, + read_indices=[0], + write_indices=[1], + readwrite_indices=[2], + type_info_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"], + type_info_named_args=["type_info", "not_present_4"], + inquiry_named_args=["inquiry", "not_present_5"], + ) + # We should onyl 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.TYPE_INFO + 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.TYPE_INFO + sig, _ = j_ref.get_signature_and_indices() + assert len(varaccesses[sig]) == 1 + assert varaccesses[sig][0].access_type == AccessType.INQUIRY + + def test_convert_argument_to_type_info(): """Test the _convert_argument_to_type_info helper function.""" # Test that if we supply a Read-only Reference it results in a TYPE_INFO. From ec75c1e17ab405301c34e046cd7e790bfb794ab9 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 11 Sep 2025 11:40:06 +0100 Subject: [PATCH 20/41] Fixed argument ordering and all named argument issues --- src/psyclone/psyir/nodes/intrinsic_call.py | 334 ++++++++++++------ .../tests/psyir/nodes/acc_directives_test.py | 2 + .../intrinsic_call_reference_accesses_test.py | 6 + 3 files changed, 228 insertions(+), 114 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index a958d01233..ae729a650b 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -146,15 +146,14 @@ def _add_typeinfo_argument( var_acc_map.add_access(sig, AccessType.TYPE_INFO, argument) -def _add_inquiry_argument( - argument: Reference, var_acc_map: VariablesAccessMap -): +def _add_inquiry_argument(argument: DataNode, var_acc_map: VariablesAccessMap): """Adds an inquiry access for argument into var_acc_map :param argument: The argument to add a inquiry access for. :param var_acc_map: The VariablesAccessMap to add the access into. """ - # FIXME For reviewer - can we have a non-Reference inquiry argument? + if not isinstance(argument, Reference): + return sig, _ = argument.get_signature_and_indices() var_acc_map.add_access(sig, AccessType.INQUIRY, argument) @@ -174,6 +173,10 @@ def _compute_reference_accesses( ) -> 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. :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` @@ -192,48 +195,65 @@ def _compute_reference_accesses( :returns: the reference accesses of node. """ reference_accesses = VariablesAccessMap() - for ind in read_indices: - arg = node.arguments[ind] - _add_read_argument(arg, reference_accesses) - for ind in write_indices: - arg = node.arguments[ind] - _add_write_argument(arg, reference_accesses) - for ind in readwrite_indices: - arg = node.arguments[ind] - _add_readwrite_argument(arg, reference_accesses) - for ind in type_info_indices: - arg = node.arguments[ind] - _add_typeinfo_argument(arg, reference_accesses) - for ind in inquiry_indices: - arg = node.arguments[ind] - _add_inquiry_argument(arg, reference_accesses) + # For indices, we only apply them if there is no argument name, othrwise + # it should be handled by the argument names. + if read_indices: + for ind in read_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] + _add_read_argument(arg, reference_accesses) + if write_indices: + for ind in write_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] + _add_write_argument(arg, reference_accesses) + if readwrite_indices: + for ind in readwrite_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] + _add_readwrite_argument(arg, reference_accesses) + if type_info_indices: + for ind in type_info_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] + _add_typeinfo_argument(arg, reference_accesses) + if inquiry_indices: + for ind in inquiry_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] + _add_inquiry_argument(arg, reference_accesses) # For each named argument provided, we check if they are defined # for the given intrinsicCall as they are optional. - for name in read_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] - _add_read_argument(arg, reference_accesses) - for name in write_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] - _add_write_argument(arg, reference_accesses) - for name in type_info_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] - _add_typeinfo_argument(arg, reference_accesses) - for name in inquiry_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] - _add_inquiry_argument(arg, reference_accesses) - for name in readwrite_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] - _add_readwrite_argument(arg, reference_accesses) + if read_named_args: + for name in read_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_read_argument(arg, reference_accesses) + if write_named_args: + for name in write_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_write_argument(arg, reference_accesses) + if type_info_named_args: + for name in type_info_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_typeinfo_argument(arg, reference_accesses) + if inquiry_named_args: + for name in inquiry_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_inquiry_argument(arg, reference_accesses) + if readwrite_named_args: + for name in readwrite_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_readwrite_argument(arg, reference_accesses) return reference_accesses @@ -1024,7 +1044,8 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], + inquiry_indices=(list(range(len(node.arguments)))), + inquiry_named_args=["pointer", "target"], ) ), ) @@ -1078,8 +1099,11 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], readwrite_indices=[0], + read_indices=[1], + write_indices=[2], + readwrite_named_args=["atom"], + read_named_args=["value"], write_named_args=["stat"], ) ), @@ -1095,8 +1119,11 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], readwrite_indices=[0], + read_indices=[1], + write_indices=[2], + readwrite_named_args=["atom"], + read_named_args=["value"], write_named_args=["stat"], ) ), @@ -1112,10 +1139,12 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, + readwrite_indices=[0], read_indices=[2, 3], write_indices=[1], - readwrite_indices=[0], - write_named_args=["stat"], + readwrite_named_args=["atom"], + write_named_args=["old", "stat"], + read_named_args=["new", "compare"], ) ), ) @@ -1130,8 +1159,11 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], readwrite_indices=[0], + read_indices=[1], + write_indices=[2], + readwrite_named_args=["atom"], + read_named_args=["value"], write_named_args=["stat"], ) ), @@ -1148,9 +1180,11 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_indices=[1], - write_indices=[2], readwrite_indices=[0], - write_named_args=["stat"], + write_indices=[2, 3], + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], ) ), ) @@ -1166,9 +1200,11 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_indices=[1], - write_indices=[2], readwrite_indices=[0], - write_named_args=["stat"], + write_indices=[2, 3], + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], ) ), ) @@ -1184,9 +1220,11 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_indices=[1], - write_indices=[2], readwrite_indices=[0], - write_named_args=["stat"], + write_indices=[2, 3], + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], ) ), ) @@ -1202,9 +1240,11 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_indices=[1], - write_indices=[2], readwrite_indices=[0], - write_named_args=["stat"], + write_indices=[2, 3], + readwrite_named_args=["atom"], + read_named_args=["value"], + write_named_args=["old", "stat"], ) ), ) @@ -1219,8 +1259,11 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], readwrite_indices=[0], + read_indices=[1], + write_indices=[2], + readwrite_named_args=["atom"], + read_named_args=["value"], write_named_args=["stat"], ) ), @@ -1237,8 +1280,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_indices=[1], - readwrite_indices=[0], - write_named_args=["stat"], + write_indices=[0, 2], + write_named_args=["value", "stat"], + read_named_args=["atom"], ) ), ) @@ -1253,8 +1297,11 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], readwrite_indices=[0], + read_indices=[1], + write_indices=[2], + readwrite_named_args=["atom"], + read_named_args=["value"], write_named_args=["stat"], ) ), @@ -1367,6 +1414,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["i"], ) ), ) @@ -1448,19 +1496,18 @@ class Intrinsic(IAttr, Enum): is_pure=True, is_elemental=False, is_inquiry=False, - required_args=ArgDesc(1, 2, DataNode), + required_args=ArgDesc(2, 2, DataNode), optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, - # If there are 2 non-optional args then the second is a - # read. - read_indices=( - [] if node.argument_names.count(None) == 1 else [1], - ), + read_indices=[1], readwrite_indices=[0], - write_names_args=["stat", "errmsg"], + write_indices=[2, 3], + readwrite_named_args=["a"], + read_named_args=["source_image"], + write_named_args=["stat", "errmsg"], ) ), ) @@ -1480,6 +1527,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, readwrite_indices=[0], + read_indices=[1], + write_indices=[2, 3], + readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], ) @@ -1501,6 +1551,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, readwrite_indices=[0], + read_indices=[1], + write_indices=[2, 3], + readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], ) @@ -1522,13 +1575,13 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, readwrite_indices=[0], - # If there are 2 non-optional args then the second is a - # read. - inquiry_indices=( - [] if node.argument_names.count(None) == 1 else [1], - ), + inquiry_indices=[1], + read_indices=[2], + write_indices=[3, 4], + readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], + inquiry_args=["operation"], ) ), ) @@ -1548,6 +1601,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, readwrite_indices=[0], + read_indices=[1], + write_indices=[2, 3], + readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], ) @@ -1630,6 +1686,8 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + type_info_indices=[1], + inquiry_named_arguments=["coarray"], type_info_named_arguments=["kind"], ) ), @@ -1658,6 +1716,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, write_indices=[0], + write_named_arguments=["time"], ) ), ) @@ -1689,6 +1748,7 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, + write_args=[0, 1, 2, 3], write_named_indices=["date", "time", "zone", "values"], ) ), @@ -1717,6 +1777,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -1816,6 +1877,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -1867,8 +1929,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_indices=[0], - write_indices=[0], - write_named_args=["stat"], + write_indices=[1, 2], + read_named_args=["event"], + write_named_args=["count", "stat"], ) ), ) @@ -1888,8 +1951,9 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0], - read_named_args=["wait"], + read_indices=[0, 1], + write_indices=[2, 3, 4], + read_named_args=["command", "wait"], write_named_args=["exitstat", "cmdstat", "cmdmsg"], ) ), @@ -1930,6 +1994,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0, 1], + inquiry_named_args=["a", "mold"], ) ), ) @@ -2035,8 +2100,10 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, + write_indices=[0, 1, 2], + readwrite_indices=[3], write_named_args=["command", "length", "status"], - readwrite_named_Args=["errmsg"], + readwrite_named_args=["errmsg"], ) ), ) @@ -2057,8 +2124,11 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_indices=[0], + write_indices=[1, 2, 3], + readwrite_indices=[4], + read_named_args=["number"], write_named_args=["value", "length", "status"], - readwrite_named_Args=["errmsg"], + readwrite_named_args=["errmsg"], ) ), ) @@ -2079,10 +2149,13 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0], + read_indices=[0, 4], + write_indices=[1, 2, 3], + readwrite_indices=[5], + read_named_args=["name"], write_named_args=["value", "length", "status"], read_named_args=["trim_name"], - readwrite_named_Args=["errmsg"], + readwrite_named_args=["errmsg"], ) ), ) @@ -2344,6 +2417,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["array"], ) ), ) @@ -2407,6 +2481,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -2418,8 +2493,16 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=( - _reference_accesses_all_reads_with_optional_kind + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + read_indices=[1], + type_info_indices=[2], + inquiry_named_args=["array"], + read_named_args=["dim"], + type_info_named_args=["kind"], + ) ), ) LCOBOUND = IAttr( @@ -2430,8 +2513,16 @@ class Intrinsic(IAttr, Enum): required_args=ArgDesc(1, 1, (DataNode)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, - reference_accesses=( - _reference_accesses_all_reads_with_optional_kind + reference_accesses=lambda node: ( + _compute_reference_accesses( + node, + inquiry_indices=[0], + read_indices=[1], + type_info_indices=[2], + inquiry_named_args=["coarray"], + read_named_args=["dim"], + type_info_named_args=["kind"], + ) ), ) LEADZ = IAttr( @@ -2626,6 +2717,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -2708,6 +2800,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -2777,10 +2870,10 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - write_indices=[1], - write_named_args=["stat"], - readwrite_named_args=["errmsg"], + readwrite_indices=[0, 3], + write_indices=[1, 2], + write_named_args=["to", "stat"], + readwrite_named_args=["from", "errmsg"], ) ), ) @@ -2797,6 +2890,8 @@ class Intrinsic(IAttr, Enum): node, read_indices=[0, 1, 2, 4], write_indices=[3], + read_named_args=["from", "frompos", "len", "topos"], + write_named_args=["to"], ) ), ) @@ -2824,6 +2919,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["c"], ) ), ) @@ -2882,6 +2978,7 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, + type_info_indices=[0], type_info_named_args=["mold"], ) ), @@ -2909,9 +3006,10 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0], + read_indices=[0, 2], type_info_indices=[1], - read_named_args=["round"], + read_named_args=["x", "round"], + type_info_named_args=["mold"], ) ), ) @@ -2981,6 +3079,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -2996,6 +3095,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["a"], ) ), ) @@ -3027,6 +3127,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -3054,6 +3155,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, write_indices=[0], + write_named_args=["harvest"], ) ), ) @@ -3068,6 +3170,8 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, + write_indices=[0, 2], + read_indices=[1], read_named_args=["put"], write_named_args=["size", "get"], ) @@ -3085,6 +3189,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -3100,6 +3205,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["a"], ) ), ) @@ -3189,7 +3295,8 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], + inquiry_indices=[0, 1], + inquiry_named_args=["a", "b"], ) ), ) @@ -3299,7 +3406,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], - typeinfo_named_args=["kind"], + type_info_indices=[1], + inquiry_named_args=["source"], + type_info_named_args=["kind"], ) ), ) @@ -3387,8 +3496,11 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + read_indices=[1], + type_info_indices=[2], + inquiry_named_args=["array"], read_named_args=["dim"], - typeinfo_named_args=["kind"], + type_info_named_args=["kind"], ) ), ) @@ -3404,6 +3516,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -3471,6 +3584,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + type_info_indices=[1], + inquiry_named_args=["a"], + type_info_named_args=["kind"], ) ), ) @@ -3507,6 +3623,7 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, + write_indices=[0, 1, 2], write_named_args=[ "count", "count_rate", @@ -3580,6 +3697,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + inquiry_named_args=["x"], ) ), ) @@ -3665,6 +3783,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + read_indices=[1], + type_info_indices=[2], + inquiry_named_args=["array"], read_named_args=["dim"], type_info_named_args=["kind"], ) @@ -3682,6 +3803,9 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_indices=[0], + read_indices=[1], + type_info_indices=[2], + inquiry_named_args=["array"], read_named_args=["dim"], type_info_named_args=["kind"], ) @@ -3820,7 +3944,6 @@ def create(cls, intrinsic, arguments=()): """ call = IntrinsicCall(intrinsic) - if not isinstance(arguments, Iterable): raise TypeError( f"IntrinsicCall.create() 'arguments' argument should be an " @@ -3914,24 +4037,7 @@ def reference_accesses(self) -> VariablesAccessMap: (a sequence of AccessTypes). """ - 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 + 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/psyir/nodes/acc_directives_test.py b/src/psyclone/tests/psyir/nodes/acc_directives_test.py index 4eee93444c..32597c4c31 100644 --- a/src/psyclone/tests/psyir/nodes/acc_directives_test.py +++ b/src/psyclone/tests/psyir/nodes/acc_directives_test.py @@ -688,6 +688,8 @@ def test_accdatadirective_update_data_movement_clauses(fortran_reader, " sto_tmp(ji) = sfactor * sto_tmp(ji)\n" "end do\n" "end program dtype_read\n") + print(psyir.view()) + print(psyir.debug_string()) loop = psyir.walk(Loop)[0] dtrans = ACCDataTrans() dtrans.apply(loop) 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 index 65ff5d4990..6a74c6e747 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -207,6 +207,12 @@ def test_add_inquiry_argument(): 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_inquiry_argument(lit, vam) + assert len(vam) == 0 + # FIXME Test _compute_reference_accesses def test_compute_reference_accesses(): From 9335f5e53e54350786010e3283e15c1104a9d75f Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 11 Sep 2025 13:28:31 +0100 Subject: [PATCH 21/41] Fixes to failing tests --- src/psyclone/psyir/nodes/intrinsic_call.py | 13 ++++++++----- .../nodes/intrinsic_call_reference_accesses_test.py | 11 +++++++++++ .../tests/psyir/nodes/intrinsic_call_test.py | 2 +- .../psyir/transformations/transformations_test.py | 3 ++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index ae729a650b..9200964bf0 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -154,7 +154,11 @@ def _add_inquiry_argument(argument: DataNode, var_acc_map: VariablesAccessMap): """ if not isinstance(argument, Reference): return - sig, _ = argument.get_signature_and_indices() + sig, all_indices = argument.get_signature_and_indices() + # For Array accesses, these have reads to their indices + for indices in all_indices: + for index in indices: + var_acc_map.update(index.reference_accesses()) var_acc_map.add_access(sig, AccessType.INQUIRY, argument) @@ -1748,8 +1752,8 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - write_args=[0, 1, 2, 3], - write_named_indices=["date", "time", "zone", "values"], + write_indices=[0, 1, 2, 3], + write_named_args=["date", "time", "zone", "values"], ) ), ) @@ -2152,9 +2156,8 @@ class Intrinsic(IAttr, Enum): read_indices=[0, 4], write_indices=[1, 2, 3], readwrite_indices=[5], - read_named_args=["name"], + read_named_args=["name", "trim_name"], write_named_args=["value", "length", "status"], - read_named_args=["trim_name"], readwrite_named_args=["errmsg"], ) ), 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 index 6a74c6e747..93301807a9 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -213,6 +213,17 @@ def test_add_inquiry_argument(): _add_inquiry_argument(lit, vam) assert len(vam) == 0 + symbol = DataSymbol("c", ArrayType(INTEGER_TYPE, [2])) + aref = ArrayReference.create(symbol, [ref]) + vam = VariablesAccessMap() + _add_inquiry_argument(aref, vam) + 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 + # FIXME Test _compute_reference_accesses def test_compute_reference_accesses(): diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 781c0b41fd..dd85361094 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -584,7 +584,7 @@ def test_reference_accesses_bounds(operator, fortran_reader): # The access to 'a' should be reported as 'NO_DATA_ACCESS' as its # actual data is not accessed. vam = schedule.reference_accesses() - assert str(vam) == "a: INQUIRY, b: READ, n: WRITE" + assert str(vam) == "b: READ, a: INQUIRY, n: WRITE" def test_enumerator_name_matches_name_field(): diff --git a/src/psyclone/tests/psyir/transformations/transformations_test.py b/src/psyclone/tests/psyir/transformations/transformations_test.py index e340e0a97f..a0dbbb03b8 100644 --- a/src/psyclone/tests/psyir/transformations/transformations_test.py +++ b/src/psyclone/tests/psyir/transformations/transformations_test.py @@ -133,6 +133,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) @@ -145,7 +146,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) = GET_COMMAND(command) end do end do end subroutine From a7ccd0d91120d0e034520313e910abce319f6d6e Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 3 Dec 2025 14:56:08 +0000 Subject: [PATCH 22/41] Fixed reference accesses to use argument names --- src/psyclone/psyir/nodes/intrinsic_call.py | 153 ++++----------------- 1 file changed, 25 insertions(+), 128 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 192be287c5..e84a4d75a0 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -815,14 +815,11 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - # All the arguments before a keyword - # argument are write indices. - write_indices=list( - range( - len(node.arguments) - - node.argument_names[::-1].index(None) - ) - ), + # All the unnamed arguments + # are write indices. + write_indices=[i for x, i in enumerate( + node.argument_names) if x is None + ], read_named_args=["mold", "source"], write_named_args=["stat", "errmsg"], ) @@ -843,14 +840,11 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - # All the arguments before a keyword - # argument are write indices. - write_indices=list( - range( - len(node.arguments) - - node.argument_names[::-1].index(None) - ) - ), + # All the unnamed arguments + # are write indices. + write_indices=[i for x, i in enumerate( + node.argument_names) if x is None + ], write_named_args=["stat"], ) ), @@ -870,6 +864,7 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, + # All arguments are unamed and all are written to. write_indices=list(range(len(node.arguments))), ) ), @@ -1152,7 +1147,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=(list(range(len(node.arguments)))), inquiry_named_args=["pointer", "target"], ) ), @@ -1220,9 +1214,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], @@ -1244,9 +1235,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], @@ -1271,9 +1259,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[2, 3], - write_indices=[1], readwrite_named_args=["atom"], write_named_args=["old", "stat"], read_named_args=["new", "compare"], @@ -1295,9 +1280,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], @@ -1322,9 +1304,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], - readwrite_indices=[0], - write_indices=[2, 3], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], @@ -1349,9 +1328,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], - readwrite_indices=[0], - write_indices=[2, 3], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], @@ -1376,9 +1352,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], - readwrite_indices=[0], - write_indices=[2, 3], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], @@ -1403,9 +1376,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], - readwrite_indices=[0], - write_indices=[2, 3], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], @@ -1427,9 +1397,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], @@ -1451,8 +1418,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], - write_indices=[0, 2], write_named_args=["value", "stat"], read_named_args=["atom"], ) @@ -1473,9 +1438,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2], readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], @@ -1661,7 +1623,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["i"], ) ), @@ -1785,9 +1746,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[1], - readwrite_indices=[0], - write_indices=[2, 3], readwrite_named_args=["a"], read_named_args=["source_image"], write_named_args=["stat", "errmsg"], @@ -1811,9 +1769,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2, 3], readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], @@ -1837,9 +1792,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2, 3], readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], @@ -1866,10 +1818,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - inquiry_indices=[1], - read_indices=[2], - write_indices=[3, 4], readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], @@ -1894,9 +1842,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0], - read_indices=[1], - write_indices=[2, 3], readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], @@ -2000,8 +1945,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - type_info_indices=[1], inquiry_named_arguments=["coarray"], type_info_named_arguments=["kind"], ) @@ -2042,7 +1985,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - write_indices=[0], write_named_arguments=["time"], ) ), @@ -2083,7 +2025,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - write_indices=[0, 1, 2, 3], write_named_args=["date", "time", "zone", "values"], ) ), @@ -2119,7 +2060,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -2247,7 +2187,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -2327,8 +2266,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0], - write_indices=[1, 2], read_named_args=["event"], write_named_args=["count", "stat"], ) @@ -2354,8 +2291,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0, 1], - write_indices=[2, 3, 4], read_named_args=["command", "wait"], write_named_args=["exitstat", "cmdstat", "cmdmsg"], ) @@ -2408,7 +2343,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0, 1], inquiry_named_args=["a", "mold"], ) ), @@ -2547,8 +2481,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - write_indices=[0, 1, 2], - readwrite_indices=[3], write_named_args=["command", "length", "status"], readwrite_named_args=["errmsg"], ) @@ -2574,9 +2506,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0], - write_indices=[1, 2, 3], - readwrite_indices=[4], read_named_args=["number"], write_named_args=["value", "length", "status"], readwrite_named_args=["errmsg"], @@ -2604,9 +2533,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0, 4], - write_indices=[1, 2, 3], - readwrite_indices=[5], read_named_args=["name", "trim_name"], write_named_args=["value", "length", "status"], readwrite_named_args=["errmsg"], @@ -2972,7 +2898,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["array"], ) ), @@ -3056,7 +2981,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -3076,9 +3000,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - read_indices=[1], - type_info_indices=[2], inquiry_named_args=["array"], read_named_args=["dim"], type_info_named_args=["kind"], @@ -3100,9 +3021,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - read_indices=[1], - type_info_indices=[2], inquiry_named_args=["coarray"], read_named_args=["dim"], type_info_named_args=["kind"], @@ -3393,7 +3311,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -3513,7 +3430,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -3613,8 +3529,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - readwrite_indices=[0, 3], - write_indices=[1, 2], write_named_args=["to", "stat"], readwrite_named_args=["from", "errmsg"], ) @@ -3638,8 +3552,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0, 1, 2, 4], - write_indices=[3], read_named_args=["from", "frompos", "len", "topos"], write_named_args=["to"], ) @@ -3676,7 +3588,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["c"], ) ), @@ -3757,7 +3668,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - type_info_indices=[0], type_info_named_args=["mold"], ) ), @@ -3794,8 +3704,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - read_indices=[0, 2], - type_info_indices=[1], read_named_args=["x", "round"], type_info_named_args=["mold"], ) @@ -3889,7 +3797,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -3909,7 +3816,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["a"], ) ), @@ -3955,7 +3861,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -3992,7 +3897,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - write_indices=[0], write_named_args=["harvest"], ) ), @@ -4012,8 +3916,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - write_indices=[0, 2], - read_indices=[1], read_named_args=["put"], write_named_args=["size", "get"], ) @@ -4034,7 +3936,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -4054,7 +3955,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["a"], ) ), @@ -4171,7 +4071,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0, 1], inquiry_named_args=["a", "b"], ) ), @@ -4300,8 +4199,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - type_info_indices=[1], inquiry_named_args=["source"], type_info_named_args=["kind"], ) @@ -4422,9 +4319,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - read_indices=[1], - type_info_indices=[2], inquiry_named_args=["array"], read_named_args=["dim"], type_info_named_args=["kind"], @@ -4446,7 +4340,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -4534,8 +4427,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - type_info_indices=[1], inquiry_named_args=["a"], type_info_named_args=["kind"], ) @@ -4584,7 +4475,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - write_indices=[0, 1, 2], write_named_args=[ "count", "count_rate", @@ -4676,7 +4566,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], inquiry_named_args=["x"], ) ), @@ -4776,9 +4665,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - read_indices=[1], - type_info_indices=[2], inquiry_named_args=["array"], read_named_args=["dim"], type_info_named_args=["kind"], @@ -4800,9 +4686,6 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - inquiry_indices=[0], - read_indices=[1], - type_info_indices=[2], inquiry_named_args=["array"], read_named_args=["dim"], type_info_named_args=["kind"], @@ -5261,7 +5144,21 @@ def reference_accesses(self) -> VariablesAccessMap: structure acccessors) 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. """ + # 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 as err: + raise InternalError( + f"Can't compute reference accesses for " + f"{self.debug_string()} due to not being able to " + f"resolve all the argument names." + ) from err + return self.intrinsic.reference_accesses(self) # TODO #2102: Maybe the three properties below can be removed if intrinsic From 117eb4809e672ffdf91f225cb8004c92c57cec53 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 11 Dec 2025 13:04:03 +0000 Subject: [PATCH 23/41] no idea --- src/psyclone/psyir/nodes/intrinsic_call.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index e84a4d75a0..048b0a845e 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -1008,7 +1008,6 @@ class Intrinsic(IAttr, Enum): ), ) ), - reference_accesses=None, reference_accesses=( _reference_accesses_all_reads_with_optional_kind ), From 9daccbae4ac1801c283207e4838e4d129c359636 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 16 Jan 2026 13:03:12 +0000 Subject: [PATCH 24/41] Merged master --- src/psyclone/psyir/nodes/intrinsic_call.py | 58 +++++++++---------- .../nemo/transformations/acc_update_test.py | 2 +- .../tests/psyir/backend/sympy_writer_test.py | 2 +- .../intrinsic_call_reference_accesses_test.py | 34 +++++------ .../tests/psyir/nodes/intrinsic_call_test.py | 2 +- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index e6c2cc4669..325d1b89a8 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -98,7 +98,7 @@ def _add_read_argument(argument: DataNode, var_acc_map: VariablesAccessMap): # with none. for ref in argument.walk(Reference): sig, all_indices = ref.get_signature_and_indices() - var_acc_map.add_access(sig, AccessType.READ, ref, all_indices) + var_acc_map.add_access(sig, AccessType.READ, ref) def _add_write_argument(argument: Reference, var_acc_map: VariablesAccessMap): @@ -112,7 +112,7 @@ def _add_write_argument(argument: Reference, var_acc_map: VariablesAccessMap): for indices in all_indices: for index in indices: var_acc_map.update(index.reference_accesses()) - var_acc_map.add_access(sig, AccessType.WRITE, argument, all_indices) + var_acc_map.add_access(sig, AccessType.WRITE, argument) def _add_readwrite_argument( @@ -128,22 +128,22 @@ def _add_readwrite_argument( for indices in all_indices: for index in indices: var_acc_map.update(index.reference_accesses()) - var_acc_map.add_access(sig, AccessType.READWRITE, argument, all_indices) + var_acc_map.add_access(sig, AccessType.READWRITE, argument) def _add_typeinfo_argument( argument: DataNode, var_acc_map: VariablesAccessMap ): - """Adds a type_info access for argument into var_acc_map + """Adds a constant access for argument into var_acc_map - :param argument: The argument to add a type_info access for. + :param argument: The argument to add a constant access for. :param var_acc_map: The VariablesAccessMap to add the access into. """ # We can get literal as typeinfo expressions, so we skip them. if not isinstance(argument, Reference): return sig, _ = argument.get_signature_and_indices() - var_acc_map.add_access(sig, AccessType.TYPE_INFO, argument) + var_acc_map.add_access(sig, AccessType.CONSTANT, argument) def _add_inquiry_argument(argument: DataNode, var_acc_map: VariablesAccessMap): @@ -167,12 +167,12 @@ def _compute_reference_accesses( read_indices: list[int] = None, write_indices: list[int] = None, readwrite_indices: list[int] = None, - type_info_indices: list[int] = None, + constant_indices: list[int] = None, inquiry_indices: list[int] = None, read_named_args: list[str] = None, write_named_args: list[str] = None, readwrite_named_args: list[str] = None, - type_info_named_args: list[str] = None, + constant_named_args: list[str] = None, inquiry_named_args: list[str] = None, ) -> VariablesAccessMap: """General helper function for creating the reference_accesses for a @@ -186,12 +186,12 @@ def _compute_reference_accesses( :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` :param read_indices: the argument indices of each read access. :param write_indices: the argument indices of each write access. - :param type_info_indices: the argument indices of each typeinfo 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 type_info_named_args: a list of named arguments that are typeinfo + :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. @@ -216,8 +216,8 @@ def _compute_reference_accesses( if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] _add_readwrite_argument(arg, reference_accesses) - if type_info_indices: - for ind in type_info_indices: + if constant_indices: + for ind in constant_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] _add_typeinfo_argument(arg, reference_accesses) @@ -240,8 +240,8 @@ def _compute_reference_accesses( continue arg = node.arguments[node.argument_names.index(name)] _add_write_argument(arg, reference_accesses) - if type_info_named_args: - for name in type_info_named_args: + if constant_named_args: + for name in constant_named_args: if name not in node.argument_names: continue arg = node.arguments[node.argument_names.index(name)] @@ -262,11 +262,11 @@ def _compute_reference_accesses( return reference_accesses -def _convert_argument_to_type_info( +def _convert_argument_to_constant( argument: DataNode, access_info: VariablesAccessMap ) -> None: """Helper function for the common case where an argument needs to have - a TYPE_INFO access map in access_info instead of a read access. + a CONSTANT access map in access_info instead of a read access. :param argument: The argument whose access needs changing. :param access_info: The access map containing the access. @@ -276,7 +276,7 @@ def _convert_argument_to_type_info( sig, _ = argument.get_signature_and_indices() var_info = access_info[sig] try: - var_info.change_read_to_type_info() + var_info.change_read_to_constant() except InternalError: # The argument here is also used in some other way # so we do nothing as the other usage has precedence. @@ -288,7 +288,7 @@ def _reference_accesses_all_reads_with_optional_kind( ) -> 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 TYPE_INFO. + argument which is instead CONSTANT. :param node: The IntrinsicCall whose reference_accesses to compute. :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` @@ -305,7 +305,7 @@ def _reference_accesses_all_reads_with_optional_kind( accesses = arg.reference_accesses() if kind_index == i: if isinstance(arg, Reference): - _convert_argument_to_type_info(arg, accesses) + _convert_argument_to_constant(arg, accesses) reference_accesses.update(accesses) return reference_accesses @@ -1938,7 +1938,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_named_arguments=["coarray"], - type_info_named_arguments=["kind"], + constant_named_arguments=["kind"], ) ), ) @@ -2997,7 +2997,7 @@ class Intrinsic(IAttr, Enum): node, inquiry_named_args=["array"], read_named_args=["dim"], - type_info_named_args=["kind"], + constant_named_args=["kind"], ) ), ) @@ -3018,7 +3018,7 @@ class Intrinsic(IAttr, Enum): node, inquiry_named_args=["coarray"], read_named_args=["dim"], - type_info_named_args=["kind"], + constant_named_args=["kind"], ) ), ) @@ -3663,7 +3663,7 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - type_info_named_args=["mold"], + constant_named_args=["mold"], ) ), ) @@ -3700,7 +3700,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, read_named_args=["x", "round"], - type_info_named_args=["mold"], + constant_named_args=["mold"], ) ), ) @@ -4195,7 +4195,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_named_args=["source"], - type_info_named_args=["kind"], + constant_named_args=["kind"], ) ), ) @@ -4316,7 +4316,7 @@ class Intrinsic(IAttr, Enum): node, inquiry_named_args=["array"], read_named_args=["dim"], - type_info_named_args=["kind"], + constant_named_args=["kind"], ) ), ) @@ -4424,7 +4424,7 @@ class Intrinsic(IAttr, Enum): _compute_reference_accesses( node, inquiry_named_args=["a"], - type_info_named_args=["kind"], + constant_named_args=["kind"], ) ), ) @@ -4667,7 +4667,7 @@ class Intrinsic(IAttr, Enum): node, inquiry_named_args=["array"], read_named_args=["dim"], - type_info_named_args=["kind"], + constant_named_args=["kind"], ) ), ) @@ -4688,7 +4688,7 @@ class Intrinsic(IAttr, Enum): node, inquiry_named_args=["array"], read_named_args=["dim"], - type_info_named_args=["kind"], + constant_named_args=["kind"], ) ), ) diff --git a/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py b/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py index e9c674042a..8746cd57f0 100644 --- a/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py +++ b/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py @@ -320,7 +320,7 @@ def test_codeblock(fortran_reader, fortran_writer): acc_update.apply(schedule) assert isinstance(schedule[1], CodeBlock) code = fortran_writer(schedule) - assert (''' !$acc update if_present host(jpi,jpj,jpk,tmask)\n\n''' + assert (''' !$acc update if_present host(jpi,jpj,jpk)\n\n''' ''' ! PSyclone CodeBlock (unsupported code) reason:\n''' ''' ! - Unsupported statement: Open_Stmt\n''' ''' ! - Unsupported statement: Read_Stmt\n''' diff --git a/src/psyclone/tests/psyir/backend/sympy_writer_test.py b/src/psyclone/tests/psyir/backend/sympy_writer_test.py index fd1e16be4d..2e2fa517d8 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/intrinsic_call_reference_accesses_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py index 93301807a9..f1e7d8ded8 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -55,7 +55,7 @@ ) from psyclone.psyir.nodes.intrinsic_call import ( IntrinsicCall, - _convert_argument_to_type_info, + _convert_argument_to_constant, _reference_accesses_all_reads_with_optional_kind, _add_read_argument, _add_write_argument, @@ -186,7 +186,7 @@ def test_add_typeinfo_argument(): sig, _ = ref.get_signature_and_indices() assert len(vam) == 1 assert len(vam[sig]) == 1 - assert vam[sig][0].access_type == AccessType.TYPE_INFO + assert vam[sig][0].access_type == AccessType.CONSTANT # Test we skip for a Literal vam = VariablesAccessMap() @@ -256,7 +256,7 @@ def test_compute_reference_accesses(): [a_ref, b_ref, c_ref, d_ref, e_ref, ("read", f_ref), ("write", g_ref), ("readwrite", h_ref), - ("type_info", i_ref), + ("constant", i_ref), ("inquiry", j_ref), ] ) @@ -265,12 +265,12 @@ def test_compute_reference_accesses(): read_indices=[0], write_indices=[1], readwrite_indices=[2], - type_info_indices=[3], + 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"], - type_info_named_args=["type_info", "not_present_4"], + constant_named_args=["constant", "not_present_4"], inquiry_named_args=["inquiry", "not_present_5"], ) # We should onyl get the 10 accesses present in the Call. @@ -287,7 +287,7 @@ def test_compute_reference_accesses(): 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.TYPE_INFO + 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 @@ -302,30 +302,30 @@ def test_compute_reference_accesses(): 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.TYPE_INFO + 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_convert_argument_to_type_info(): - """Test the _convert_argument_to_type_info helper function.""" - # Test that if we supply a Read-only Reference it results in a TYPE_INFO. +def test_convert_argument_to_constant(): + """Test the _convert_argument_to_constant helper function.""" + # Test that if we supply a Read-only Reference it results in a CONSTANT. symbol = DataSymbol("a", INTEGER_TYPE) ref = Reference(symbol) accesses = ref.reference_accesses() sig, _ = ref.get_signature_and_indices() assert accesses[sig].is_read_only - _convert_argument_to_type_info(ref, accesses) - assert accesses[sig][0].access_type == AccessType.TYPE_INFO + _convert_argument_to_constant(ref, accesses) + assert accesses[sig][0].access_type == AccessType.CONSTANT - # Test if we supply a mixed read/write reference we don't get a TYPE_INFO. + # Test if we supply a mixed read/write reference we don't get a CONSTANT. assign = Assignment.create(Reference(symbol), Reference(symbol)) accesses = assign.reference_accesses() - _convert_argument_to_type_info(assign.lhs, accesses) + _convert_argument_to_constant(assign.lhs, accesses) sig, _ = assign.lhs.get_signature_and_indices() for access in accesses[sig]: - assert access.access_type != AccessType.TYPE_INFO + assert access.access_type != AccessType.CONSTANT def test_reference_accesses_all_reads_with_optional_kind(fortran_reader): @@ -347,8 +347,8 @@ def test_reference_accesses_all_reads_with_optional_kind(fortran_reader): 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 TYPE_INFO + # 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.TYPE_INFO + 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 74fe1731ac..b28f8791a1 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -618,7 +618,7 @@ def test_reference_accesses_bounds(operator, fortran_reader): # The access to 'a' should be reported as 'INQUIRY' as its # actual data is not accessed. vam = schedule.reference_accesses() - assert str(vam) == "b: READ, a: INQUIRY, n: WRITE" + assert str(vam) == "a: INQUIRY, b: READ, n: WRITE" def test_enumerator_name_matches_name_field(): From d51d49a5b35cbc1705ec4da83aac6f4225187b7f Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 16 Jan 2026 15:28:20 +0000 Subject: [PATCH 25/41] Changes for first indirect changes --- src/psyclone/psyir/nodes/intrinsic_call.py | 4 ++-- .../tests/psyir/nodes/intrinsic_call_test.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 325d1b89a8..ba6886ec0d 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -5168,8 +5168,8 @@ def reference_accesses(self) -> VariablesAccessMap: except NotImplementedError as err: raise InternalError( f"Can't compute reference accesses for " - f"{self.debug_string()} due to not being able to " - f"resolve all the argument names." + f"'{self.debug_string().rstrip()}' due to not being " + f"able to resolve all the argument names." ) from err return self.intrinsic.reference_accesses(self) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index b28f8791a1..4bb976b667 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -173,6 +173,20 @@ def test_intrinsiccall_datatype(fortran_reader): assert isinstance(call.datatype, UnresolvedType) +def test_intrinsiccall_reference_accesses_error(): + """Tests the reference_accesses method of intrinsiccall's error + case.""" + # Test computing argument names doesn't work when we have 2 arguments for + # SUM with no naming, as it can't determine between the SUM variants. + intrinsic = IntrinsicCall(IntrinsicCall.Intrinsic.SUM) + intrinsic.addchild(Reference(DataSymbol("a", INTEGER_TYPE))) + intrinsic.addchild(Reference(DataSymbol("a", INTEGER_TYPE))) + with pytest.raises(InternalError) as err: + _ = intrinsic.reference_accesses() + assert ("Can't compute reference accesses for 'SUM(a, a)' due to not " + "being able to resolve all the argument names." in str(err.value)) + + 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 From af2b4fce49d39f2067ad739d60ccf6700331de54 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Mon, 19 Jan 2026 09:55:51 +0000 Subject: [PATCH 26/41] Indirect coverage changes --- src/psyclone/psyir/nodes/intrinsic_call.py | 8 ++++---- src/psyclone/tests/psyir/nodes/omp_directives_test.py | 5 +++-- .../psyir/transformations/scalarisation_trans_test.py | 8 +++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index ba6886ec0d..1f15ca727d 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -818,8 +818,8 @@ class Intrinsic(IAttr, Enum): node, # All the unnamed arguments # are write indices. - write_indices=[i for x, i in enumerate( - node.argument_names) if x is None + 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"], @@ -843,8 +843,8 @@ class Intrinsic(IAttr, Enum): node, # All the unnamed arguments # are write indices. - write_indices=[i for x, i in enumerate( - node.argument_names) if x is None + write_indices=[x for x, i in enumerate( + node.argument_names) if i is None ], write_named_args=["stat"], ) diff --git a/src/psyclone/tests/psyir/nodes/omp_directives_test.py b/src/psyclone/tests/psyir/nodes/omp_directives_test.py index a3d59db08e..a7b58a2150 100644 --- a/src/psyclone/tests/psyir/nodes/omp_directives_test.py +++ b/src/psyclone/tests/psyir/nodes/omp_directives_test.py @@ -935,13 +935,14 @@ def test_infer_sharing_attributes(fortran_reader): assert list(sync)[0].name == 'k' # Check that kinds on literals are ignored for data sharing clauses + # and that if any access to a varible is CONSTANT it is ignored. 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/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 From 34f5b68b805c25335541edabb2c261db0835e860 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Mon, 19 Jan 2026 10:02:59 +0000 Subject: [PATCH 27/41] indirect fixes --- .../psyir/transformations/omp_target_trans_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 0377e71062..f36b12d195 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""" From dec435ed385aa88e7061869ea5e9a55340fcc367 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Mon, 19 Jan 2026 10:51:25 +0000 Subject: [PATCH 28/41] Fixed failing test --- .../tests/domain/nemo/transformations/acc_update_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py b/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py index 8746cd57f0..e9c674042a 100644 --- a/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py +++ b/src/psyclone/tests/domain/nemo/transformations/acc_update_test.py @@ -320,7 +320,7 @@ def test_codeblock(fortran_reader, fortran_writer): acc_update.apply(schedule) assert isinstance(schedule[1], CodeBlock) code = fortran_writer(schedule) - assert (''' !$acc update if_present host(jpi,jpj,jpk)\n\n''' + assert (''' !$acc update if_present host(jpi,jpj,jpk,tmask)\n\n''' ''' ! PSyclone CodeBlock (unsupported code) reason:\n''' ''' ! - Unsupported statement: Open_Stmt\n''' ''' ! - Unsupported statement: Read_Stmt\n''' From 4f0206988d28147dcb0171de459e48f493f27d38 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Mon, 19 Jan 2026 11:29:03 +0000 Subject: [PATCH 29/41] Renamed remaining bad function name --- src/psyclone/psyir/nodes/intrinsic_call.py | 6 +++--- .../nodes/intrinsic_call_reference_accesses_test.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 1f15ca727d..f9a9155875 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -131,7 +131,7 @@ def _add_readwrite_argument( var_acc_map.add_access(sig, AccessType.READWRITE, argument) -def _add_typeinfo_argument( +def _add_constant_argument( argument: DataNode, var_acc_map: VariablesAccessMap ): """Adds a constant access for argument into var_acc_map @@ -220,7 +220,7 @@ def _compute_reference_accesses( for ind in constant_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] - _add_typeinfo_argument(arg, reference_accesses) + _add_constant_argument(arg, reference_accesses) if inquiry_indices: for ind in inquiry_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: @@ -245,7 +245,7 @@ def _compute_reference_accesses( if name not in node.argument_names: continue arg = node.arguments[node.argument_names.index(name)] - _add_typeinfo_argument(arg, reference_accesses) + _add_constant_argument(arg, reference_accesses) if inquiry_named_args: for name in inquiry_named_args: if name not in node.argument_names: 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 index f1e7d8ded8..730e570238 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -60,7 +60,7 @@ _add_read_argument, _add_write_argument, _add_readwrite_argument, - _add_typeinfo_argument, + _add_constant_argument, _add_inquiry_argument, _compute_reference_accesses, ) @@ -175,13 +175,13 @@ def test_add_readwrite_argument(): assert vam[sig][0].access_type == AccessType.READ -def test_add_typeinfo_argument(): - """ Test the _add_typeinfo_argument helper function.""" +def test_add_constant_argument(): + """ Test the _add_constant_argument helper function.""" # Test we get expected behaviour for a Reference input. symbol = DataSymbol("a", INTEGER_TYPE) vam = VariablesAccessMap() ref = Reference(symbol) - _add_typeinfo_argument(ref, vam) + _add_constant_argument(ref, vam) sig, _ = ref.get_signature_and_indices() assert len(vam) == 1 @@ -191,7 +191,7 @@ def test_add_typeinfo_argument(): # Test we skip for a Literal vam = VariablesAccessMap() lit = Literal("1", INTEGER_TYPE) - _add_typeinfo_argument(lit, vam) + _add_constant_argument(lit, vam) assert len(vam) == 0 From f1fe6eb1269c4ade1c00a9a49f6b18a6472dd5ae Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 21 Jan 2026 13:43:49 +0000 Subject: [PATCH 30/41] Updates towards review --- src/psyclone/psyir/nodes/intrinsic_call.py | 34 ++++++++-------- .../tests/psyir/nodes/acc_directives_test.py | 2 - .../intrinsic_call_reference_accesses_test.py | 40 ++++++++++++++++--- .../tests/psyir/nodes/intrinsic_call_test.py | 7 ++-- .../tests/psyir/nodes/omp_directives_test.py | 4 +- .../transformations/omp_target_trans_test.py | 2 +- .../transformations/transformations_test.py | 2 +- 7 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index f9a9155875..05e96cb9b0 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -87,7 +87,9 @@ ArgDesc = namedtuple('ArgDesc', 'min_count max_count types arg_names') -def _add_read_argument(argument: DataNode, var_acc_map: VariablesAccessMap): +def _add_read_argument( + argument: DataNode, var_acc_map: VariablesAccessMap +) -> None: """Adds a read access for argument into var_acc_map :param argument: The argument to add a read access for. @@ -96,19 +98,20 @@ def _add_read_argument(argument: DataNode, var_acc_map: VariablesAccessMap): # Find all the reference children of the argument (e.g. we could # have a binary operation argument with multiple, or a Literal # with none. - for ref in argument.walk(Reference): - sig, all_indices = ref.get_signature_and_indices() - var_acc_map.add_access(sig, AccessType.READ, ref) + argument_map = argument.reference_accesses() + var_acc_map.update(argument_map) -def _add_write_argument(argument: Reference, var_acc_map: VariablesAccessMap): +def _add_write_argument( + argument: Reference, var_acc_map: VariablesAccessMap +) -> None: """Adds a write access for argument into var_acc_map :param argument: The argument to add a write access for. :param var_acc_map: The VariablesAccessMap to add the access into. """ sig, all_indices = argument.get_signature_and_indices() - # For Array accesses, these have reads to their indices + # For Array accesses, these have accesses to their indices for indices in all_indices: for index in indices: var_acc_map.update(index.reference_accesses()) @@ -117,14 +120,14 @@ def _add_write_argument(argument: Reference, var_acc_map: VariablesAccessMap): def _add_readwrite_argument( argument: Reference, var_acc_map: VariablesAccessMap -): +) -> None: """Adds a readwrite access for argument into var_acc_map :param argument: The argument to add a readwrite access for. :param var_acc_map: The VariablesAccessMap to add the access into. """ sig, all_indices = argument.get_signature_and_indices() - # For Array accesses, these have reads to their indices + # For Array accesses, these have accesses to their indices for indices in all_indices: for index in indices: var_acc_map.update(index.reference_accesses()) @@ -132,8 +135,8 @@ def _add_readwrite_argument( def _add_constant_argument( - argument: DataNode, var_acc_map: VariablesAccessMap -): + argument: Union[Literal, Reference], var_acc_map: VariablesAccessMap +) -> None: """Adds a constant access for argument into var_acc_map :param argument: The argument to add a constant access for. @@ -146,7 +149,9 @@ def _add_constant_argument( var_acc_map.add_access(sig, AccessType.CONSTANT, argument) -def _add_inquiry_argument(argument: DataNode, var_acc_map: VariablesAccessMap): +def _add_inquiry_argument( + argument: Union[Literal, Reference], var_acc_map: VariablesAccessMap +) -> None: """Adds an inquiry access for argument into var_acc_map :param argument: The argument to add a inquiry access for. @@ -155,7 +160,7 @@ def _add_inquiry_argument(argument: DataNode, var_acc_map: VariablesAccessMap): if not isinstance(argument, Reference): return sig, all_indices = argument.get_signature_and_indices() - # For Array accesses, these have reads to their indices + # For Array accesses, these have accesses to their indices for indices in all_indices: for index in indices: var_acc_map.update(index.reference_accesses()) @@ -163,7 +168,7 @@ def _add_inquiry_argument(argument: DataNode, var_acc_map: VariablesAccessMap): def _compute_reference_accesses( - node, + node : "IntrinsicCall", read_indices: list[int] = None, write_indices: list[int] = None, readwrite_indices: list[int] = None, @@ -183,7 +188,6 @@ def _compute_reference_accesses( contains the name. :param node: the IntrinsicCall whose reference_accesses to compute. - :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` :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. @@ -794,8 +798,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, diff --git a/src/psyclone/tests/psyir/nodes/acc_directives_test.py b/src/psyclone/tests/psyir/nodes/acc_directives_test.py index 90b9a73207..4ea65a8854 100644 --- a/src/psyclone/tests/psyir/nodes/acc_directives_test.py +++ b/src/psyclone/tests/psyir/nodes/acc_directives_test.py @@ -688,8 +688,6 @@ def test_accdatadirective_update_data_movement_clauses(fortran_reader, " sto_tmp(ji) = sfactor * sto_tmp(ji)\n" "end do\n" "end program dtype_read\n") - print(psyir.view()) - print(psyir.debug_string()) loop = psyir.walk(Loop)[0] dtrans = ACCDataTrans() dtrans.apply(loop) 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 index 730e570238..978a4417dd 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2022-2025, Science and Technology Facilities Council. +# Copyright (c) 2022-2026, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -42,8 +42,6 @@ """ -# import pytest - from psyclone.core import AccessType, VariablesAccessMap from psyclone.psyir.nodes import ( ArrayReference, @@ -72,7 +70,7 @@ ) -def test_add_read_argument(): +def test_add_read_argument(fortran_reader): """ Test the _add_read_argument helper function.""" # Test we get expected behaviour for a Reference input. symbol = DataSymbol("a", INTEGER_TYPE) @@ -124,6 +122,37 @@ def test_add_read_argument(): 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_read_argument(intrinsic.arguments[1], vam) + sigs = vam.all_signatures + print(sigs) + #[Signature(b), Signature(c), Signature(d), Signature(some_func), Signature(wp)] + 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_write_argument(): """ Test the _add_write_argument helper function.""" @@ -225,7 +254,6 @@ def test_add_inquiry_argument(): assert vam[sig][0].access_type == AccessType.READ -# FIXME Test _compute_reference_accesses def test_compute_reference_accesses(): """ Test the _compute_reference_accesses helper function.""" # Create some References to use to test functionality. @@ -273,7 +301,7 @@ def test_compute_reference_accesses(): constant_named_args=["constant", "not_present_4"], inquiry_named_args=["inquiry", "not_present_5"], ) - # We should onyl get the 10 accesses present in the Call. + # We should only get the 10 accesses present in the Call. assert len(varaccesses) == 10 sig, _ = a_ref.get_signature_and_indices() diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index 4bb976b667..78401bdd74 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -174,10 +174,9 @@ def test_intrinsiccall_datatype(fortran_reader): def test_intrinsiccall_reference_accesses_error(): - """Tests the reference_accesses method of intrinsiccall's error - case.""" - # Test computing argument names doesn't work when we have 2 arguments for - # SUM with no naming, as it can't determine between the SUM variants. + """Test the error case of IntrinsicCall's reference_accesses method.""" + # 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) intrinsic.addchild(Reference(DataSymbol("a", INTEGER_TYPE))) intrinsic.addchild(Reference(DataSymbol("a", INTEGER_TYPE))) diff --git a/src/psyclone/tests/psyir/nodes/omp_directives_test.py b/src/psyclone/tests/psyir/nodes/omp_directives_test.py index a7b58a2150..bfb0aca5e6 100644 --- a/src/psyclone/tests/psyir/nodes/omp_directives_test.py +++ b/src/psyclone/tests/psyir/nodes/omp_directives_test.py @@ -934,8 +934,8 @@ 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 - # and that if any access to a varible is CONSTANT it is ignored. + # 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 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 f36b12d195..06bfbec92f 100644 --- a/src/psyclone/tests/psyir/transformations/omp_target_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/omp_target_trans_test.py @@ -445,7 +445,7 @@ def test_omptarget_nowait_multiple_dependencies(fortran_reader, def test_kind_parameters_ignored(fortran_reader): - '''Test that CONSTANT variables used in locations that would also + '''Test that CONSTANT variables used in locations that would also be attributed as reads don't result in dependencies.''' code = """ subroutine x() diff --git a/src/psyclone/tests/psyir/transformations/transformations_test.py b/src/psyclone/tests/psyir/transformations/transformations_test.py index 174f449ae9..fff90470dd 100644 --- a/src/psyclone/tests/psyir/transformations/transformations_test.py +++ b/src/psyclone/tests/psyir/transformations/transformations_test.py @@ -147,7 +147,7 @@ def test_accparalleltrans_validate(fortran_reader): end do do i = 1, 10 do j = 1, 10 - A(i,j) = GET_COMMAND(command) + A(i,j) = GET_COMMAND(2) end do end do end subroutine From eaa2936825d8dd1cccc6cc5b34304a1f4cfdd3cf Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 21 Jan 2026 13:58:20 +0000 Subject: [PATCH 31/41] Additional test --- src/psyclone/psyir/nodes/intrinsic_call.py | 2 +- .../intrinsic_call_reference_accesses_test.py | 37 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 05e96cb9b0..16d9a24ad6 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -168,7 +168,7 @@ def _add_inquiry_argument( def _compute_reference_accesses( - node : "IntrinsicCall", + node: "IntrinsicCall", read_indices: list[int] = None, write_indices: list[int] = None, readwrite_indices: list[int] = None, 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 index 978a4417dd..9910764951 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -135,8 +135,6 @@ def test_add_read_argument(fortran_reader): vam = VariablesAccessMap() _add_read_argument(intrinsic.arguments[1], vam) sigs = vam.all_signatures - print(sigs) - #[Signature(b), Signature(c), Signature(d), Signature(some_func), Signature(wp)] assert str(sigs[0]) == "b" assert len(vam[sigs[0]]) == 1 assert vam[sigs[0]][0].access_type == AccessType.READ @@ -154,7 +152,7 @@ def test_add_read_argument(fortran_reader): assert vam[sigs[4]][0].access_type == AccessType.CONSTANT -def test_add_write_argument(): +def test_add_write_argument(fortran_reader): """ Test the _add_write_argument helper function.""" # Test we get expected behaviour for a Reference input. symbol = DataSymbol("a", INTEGER_TYPE) @@ -178,6 +176,39 @@ def test_add_write_argument(): 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_write_argument(intrinsic.arguments[0], vam) + 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_readwrite_argument(): """ Test the _add_readwrite_argument helper function.""" From 5430465803eb0d0c6261d5d83a2b38da1b3dcf7e Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 23 Jan 2026 11:27:35 +0000 Subject: [PATCH 32/41] First review comment --- .../tests/psyir/transformations/transformations_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/psyclone/tests/psyir/transformations/transformations_test.py b/src/psyclone/tests/psyir/transformations/transformations_test.py index fff90470dd..1b7279f657 100644 --- a/src/psyclone/tests/psyir/transformations/transformations_test.py +++ b/src/psyclone/tests/psyir/transformations/transformations_test.py @@ -147,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 @@ -168,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)) From b22f1f3c408c1a0e782c1d0ea85b1f2fb1f0fc8d Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 23 Jan 2026 11:32:23 +0000 Subject: [PATCH 33/41] Upload to check on git --- src/psyclone/psyir/nodes/intrinsic_call.py | 118 ++++++++++----------- 1 file changed, 54 insertions(+), 64 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index ae32cebead..f3be165bda 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -169,16 +169,16 @@ def _add_inquiry_argument( def _compute_reference_accesses( node: "IntrinsicCall", - read_indices: list[int] = None, - write_indices: list[int] = None, - readwrite_indices: list[int] = None, - constant_indices: list[int] = None, - inquiry_indices: list[int] = None, - read_named_args: list[str] = None, - write_named_args: list[str] = None, - readwrite_named_args: list[str] = None, - constant_named_args: list[str] = None, - inquiry_named_args: list[str] = None, + 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. @@ -205,63 +205,53 @@ def _compute_reference_accesses( reference_accesses = VariablesAccessMap() # For indices, we only apply them if there is no argument name, othrwise # it should be handled by the argument names. - if read_indices: - for ind in read_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] - _add_read_argument(arg, reference_accesses) - if write_indices: - for ind in write_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] - _add_write_argument(arg, reference_accesses) - if readwrite_indices: - for ind in readwrite_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] - _add_readwrite_argument(arg, reference_accesses) - if constant_indices: - for ind in constant_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] - _add_constant_argument(arg, reference_accesses) - if inquiry_indices: - for ind in inquiry_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] - _add_inquiry_argument(arg, reference_accesses) - # For each named argument provided, we check if they are defined - # for the given intrinsicCall as they are optional. - if read_named_args: - for name in read_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] + for ind in read_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] _add_read_argument(arg, reference_accesses) - if write_named_args: - for name in write_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] + for ind in write_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] _add_write_argument(arg, reference_accesses) - if constant_named_args: - for name in constant_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] + for ind in readwrite_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] + _add_readwrite_argument(arg, reference_accesses) + for ind in constant_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] _add_constant_argument(arg, reference_accesses) - if inquiry_named_args: - for name in inquiry_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] + for ind in inquiry_indices: + if ind < len(node.arguments) and node.argument_names[ind] is None: + arg = node.arguments[ind] _add_inquiry_argument(arg, reference_accesses) - if readwrite_named_args: - for name in readwrite_named_args: - if name not in node.argument_names: - continue - arg = node.arguments[node.argument_names.index(name)] - _add_readwrite_argument(arg, reference_accesses) + # For each named argument provided, we check if they are defined + # for the given intrinsicCall as they are optional. + for name in read_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_read_argument(arg, reference_accesses) + for name in write_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_write_argument(arg, reference_accesses) + for name in constant_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_constant_argument(arg, reference_accesses) + for name in inquiry_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_inquiry_argument(arg, reference_accesses) + for name in readwrite_named_args: + if name not in node.argument_names: + continue + arg = node.arguments[node.argument_names.index(name)] + _add_readwrite_argument(arg, reference_accesses) return reference_accesses @@ -867,7 +857,7 @@ class Intrinsic(IAttr, Enum): reference_accesses=lambda node: ( _compute_reference_accesses( node, - # All arguments are unamed and all are written to. + # All arguments are unnamed and all are written to. write_indices=list(range(len(node.arguments))), ) ), From 37a19f129d336f6697ccdf2c8ecc319d46cdcc09 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 23 Jan 2026 12:56:54 +0000 Subject: [PATCH 34/41] changes for review --- src/psyclone/psyir/nodes/intrinsic_call.py | 23 ++++++++---- .../tests/psyir/nodes/intrinsic_call_test.py | 35 +++++++++++++------ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index f3be165bda..84b3207ee0 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -5157,12 +5157,23 @@ def reference_accesses(self) -> VariablesAccessMap: if None in self.argument_names: try: self.compute_argument_names() - except NotImplementedError as err: - raise InternalError( - f"Can't compute reference accesses for " - f"'{self.debug_string().rstrip()}' due to not being " - f"able to resolve all the argument names." - ) from err + 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) diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index fd7c7b8d78..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,17 +175,30 @@ def test_intrinsiccall_datatype(fortran_reader): assert isinstance(call.datatype, UnresolvedType) -def test_intrinsiccall_reference_accesses_error(): - """Test the error case of IntrinsicCall's reference_accesses method.""" +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))) - intrinsic.addchild(Reference(DataSymbol("a", INTEGER_TYPE))) - with pytest.raises(InternalError) as err: - _ = intrinsic.reference_accesses() - assert ("Can't compute reference accesses for 'SUM(a, a)' due to not " - "being able to resolve all the argument names." in str(err.value)) + # 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(): From 8278cf86641e47ae281a44185788bfac82d13828 Mon Sep 17 00:00:00 2001 From: Sergi Siso Date: Mon, 26 Jan 2026 10:24:03 +0000 Subject: [PATCH 35/41] #3060 Remove change* access_type methods --- src/psyclone/core/access_sequence.py | 97 ++----------------- src/psyclone/psyir/nodes/assignment.py | 22 +---- src/psyclone/psyir/nodes/intrinsic_call.py | 8 +- .../tests/core/access_sequence_test.py | 97 ++----------------- .../tests/psyir/nodes/assignment_test.py | 18 ++-- 5 files changed, 34 insertions(+), 208 deletions(-) diff --git a/src/psyclone/core/access_sequence.py b/src/psyclone/core/access_sequence.py index bb572edfae..679ed8b43f 100644 --- a/src/psyclone/core/access_sequence.py +++ b/src/psyclone/core/access_sequence.py @@ -73,32 +73,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 +108,15 @@ 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)}'") + self._access_type = value + def is_any_write(self) -> bool: ''' :returns: whether this access represents a write of any kind. @@ -319,34 +302,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 @@ -364,40 +319,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 84b3207ee0..1efa9d070c 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -268,13 +268,7 @@ def _convert_argument_to_constant( # If the argument isn't a Reference then we don't do anything. if isinstance(argument, Reference): sig, _ = argument.get_signature_and_indices() - var_info = access_info[sig] - try: - var_info.change_read_to_constant() - except InternalError: - # The argument here is also used in some other way - # so we do nothing as the other usage has precedence. - pass + access_info[sig][0].access_type = AccessType.CONSTANT def _reference_accesses_all_reads_with_optional_kind( diff --git a/src/psyclone/tests/core/access_sequence_test.py b/src/psyclone/tests/core/access_sequence_test.py index a78a5a49c9..6c93114b93 100644 --- a/src/psyclone/tests/core/access_sequence_test.py +++ b/src/psyclone/tests/core/access_sequence_test.py @@ -51,39 +51,21 @@ 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()) @@ -202,7 +184,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 +192,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 +213,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/nodes/assignment_test.py b/src/psyclone/tests/psyir/nodes/assignment_test.py index d309614d03..05d07e0e3f 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,19 @@ 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 + + # The third statement also have a nested access, the implicit range has + # an implicit use of INQUIRY to find the bounds. From 8e42593139b9bf06c0b5f1ff5d78e0e0bc8eed8f Mon Sep 17 00:00:00 2001 From: Sergi Siso Date: Mon, 26 Jan 2026 10:38:18 +0000 Subject: [PATCH 36/41] #3060 Remove _convert_argument_to_constant --- src/psyclone/psyir/nodes/intrinsic_call.py | 18 ++-------------- .../intrinsic_call_reference_accesses_test.py | 21 ------------------- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 1efa9d070c..e387ddf402 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -256,21 +256,6 @@ def _compute_reference_accesses( return reference_accesses -def _convert_argument_to_constant( - argument: DataNode, access_info: VariablesAccessMap -) -> None: - """Helper function for the common case where an argument needs to have - a CONSTANT access map in access_info instead of a read access. - - :param argument: The argument whose access needs changing. - :param access_info: The access map containing the access. - """ - # If the argument isn't a Reference then we don't do anything. - if isinstance(argument, Reference): - sig, _ = argument.get_signature_and_indices() - access_info[sig][0].access_type = AccessType.CONSTANT - - def _reference_accesses_all_reads_with_optional_kind( node, ) -> VariablesAccessMap: @@ -293,7 +278,8 @@ def _reference_accesses_all_reads_with_optional_kind( accesses = arg.reference_accesses() if kind_index == i: if isinstance(arg, Reference): - _convert_argument_to_constant(arg, accesses) + sig, _ = arg.get_signature_and_indices() + accesses[sig][-1].access_type = AccessType.CONSTANT reference_accesses.update(accesses) return reference_accesses 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 index 9910764951..2ff3d124b2 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -53,7 +53,6 @@ ) from psyclone.psyir.nodes.intrinsic_call import ( IntrinsicCall, - _convert_argument_to_constant, _reference_accesses_all_reads_with_optional_kind, _add_read_argument, _add_write_argument, @@ -367,26 +366,6 @@ def test_compute_reference_accesses(): assert varaccesses[sig][0].access_type == AccessType.INQUIRY -def test_convert_argument_to_constant(): - """Test the _convert_argument_to_constant helper function.""" - # Test that if we supply a Read-only Reference it results in a CONSTANT. - symbol = DataSymbol("a", INTEGER_TYPE) - ref = Reference(symbol) - accesses = ref.reference_accesses() - sig, _ = ref.get_signature_and_indices() - assert accesses[sig].is_read_only - _convert_argument_to_constant(ref, accesses) - assert accesses[sig][0].access_type == AccessType.CONSTANT - - # Test if we supply a mixed read/write reference we don't get a CONSTANT. - assign = Assignment.create(Reference(symbol), Reference(symbol)) - accesses = assign.reference_accesses() - _convert_argument_to_constant(assign.lhs, accesses) - sig, _ = assign.lhs.get_signature_and_indices() - for access in accesses[sig]: - assert access.access_type != AccessType.CONSTANT - - def test_reference_accesses_all_reads_with_optional_kind(fortran_reader): """Test the _reference_accesses_all_reads_with_optional_kind helper function.""" From f852614db3d0741ca9bb7279372676c23f4f8422 Mon Sep 17 00:00:00 2001 From: Sergi Siso Date: Mon, 26 Jan 2026 10:49:31 +0000 Subject: [PATCH 37/41] #3060 Remove leftover comment --- src/psyclone/tests/psyir/nodes/assignment_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/psyclone/tests/psyir/nodes/assignment_test.py b/src/psyclone/tests/psyir/nodes/assignment_test.py index 05d07e0e3f..e12650813f 100644 --- a/src/psyclone/tests/psyir/nodes/assignment_test.py +++ b/src/psyclone/tests/psyir/nodes/assignment_test.py @@ -379,6 +379,3 @@ def test_reference_accesses(fortran_reader): 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 - - # The third statement also have a nested access, the implicit range has - # an implicit use of INQUIRY to find the bounds. From 2174e9a8f5ae1dcd2872f8dc990426115ed72cc7 Mon Sep 17 00:00:00 2001 From: Sergi Siso Date: Mon, 26 Jan 2026 10:52:01 +0000 Subject: [PATCH 38/41] #3060 Fix flake8 --- src/psyclone/core/access_sequence.py | 1 - src/psyclone/tests/core/access_sequence_test.py | 1 - .../tests/psyir/nodes/intrinsic_call_reference_accesses_test.py | 1 - 3 files changed, 3 deletions(-) diff --git a/src/psyclone/core/access_sequence.py b/src/psyclone/core/access_sequence.py index 679ed8b43f..74f7484faf 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 diff --git a/src/psyclone/tests/core/access_sequence_test.py b/src/psyclone/tests/core/access_sequence_test.py index 6c93114b93..d6c9f4bbd2 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) 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 index 2ff3d124b2..0fcc83d823 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -47,7 +47,6 @@ ArrayReference, Literal, Reference, - Assignment, BinaryOperation, Call ) From 41aa9a20a7d8ed3c25e82c8f38fb1d35eb365256 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 30 Jan 2026 14:41:24 +0000 Subject: [PATCH 39/41] Review updates --- src/psyclone/psyir/nodes/intrinsic_call.py | 121 +++++------------- .../intrinsic_call_reference_accesses_test.py | 61 ++++----- 2 files changed, 66 insertions(+), 116 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index e387ddf402..d351346f66 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -87,84 +87,23 @@ ArgDesc = namedtuple('ArgDesc', 'min_count max_count types arg_names') -def _add_read_argument( - argument: DataNode, var_acc_map: VariablesAccessMap +def _add_argument_of_access_type( + argument: DataNode, var_acc_map: VariablesAccessMap, + access_type: AccessType ) -> None: - """Adds a read access for argument into var_acc_map - - :param argument: The argument to add a read access for. - :param var_acc_map: The VariablesAccessMap to add the access into. - """ - # Find all the reference children of the argument (e.g. we could - # have a binary operation argument with multiple, or a Literal - # with none. - argument_map = argument.reference_accesses() - var_acc_map.update(argument_map) - - -def _add_write_argument( - argument: Reference, var_acc_map: VariablesAccessMap -) -> None: - """Adds a write access for argument into var_acc_map - - :param argument: The argument to add a write access for. - :param var_acc_map: The VariablesAccessMap to add the access into. - """ - sig, all_indices = argument.get_signature_and_indices() - # For Array accesses, these have accesses to their indices - for indices in all_indices: - for index in indices: - var_acc_map.update(index.reference_accesses()) - var_acc_map.add_access(sig, AccessType.WRITE, argument) - - -def _add_readwrite_argument( - argument: Reference, var_acc_map: VariablesAccessMap -) -> None: - """Adds a readwrite access for argument into var_acc_map - - :param argument: The argument to add a readwrite access for. - :param var_acc_map: The VariablesAccessMap to add the access into. - """ - sig, all_indices = argument.get_signature_and_indices() - # For Array accesses, these have accesses to their indices - for indices in all_indices: - for index in indices: - var_acc_map.update(index.reference_accesses()) - var_acc_map.add_access(sig, AccessType.READWRITE, argument) - - -def _add_constant_argument( - argument: Union[Literal, Reference], var_acc_map: VariablesAccessMap -) -> None: - """Adds a constant access for argument into var_acc_map - - :param argument: The argument to add a constant access for. - :param var_acc_map: The VariablesAccessMap to add the access into. - """ - # We can get literal as typeinfo expressions, so we skip them. - if not isinstance(argument, Reference): - return - sig, _ = argument.get_signature_and_indices() - var_acc_map.add_access(sig, AccessType.CONSTANT, argument) - - -def _add_inquiry_argument( - argument: Union[Literal, Reference], var_acc_map: VariablesAccessMap -) -> None: - """Adds an inquiry access for argument into var_acc_map + ''' + Adds an argument to the provided VariablesAccessMap with + the provided access_type - :param argument: The argument to add a inquiry access for. - :param var_acc_map: The VariablesAccessMap to add the access into. - """ - if not isinstance(argument, Reference): - return - sig, all_indices = argument.get_signature_and_indices() - # For Array accesses, these have accesses to their indices - for indices in all_indices: - for index in indices: - var_acc_map.update(index.reference_accesses()) - var_acc_map.add_access(sig, AccessType.INQUIRY, argument) + :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( @@ -208,50 +147,60 @@ def _compute_reference_accesses( for ind in read_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] - _add_read_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READ) for ind in write_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] - _add_write_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.WRITE) for ind in readwrite_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] - _add_readwrite_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READWRITE) for ind in constant_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] - _add_constant_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.CONSTANT) for ind in inquiry_indices: if ind < len(node.arguments) and node.argument_names[ind] is None: arg = node.arguments[ind] - _add_inquiry_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.INQUIRY) # For each named argument provided, we check if they are defined # for the given intrinsicCall as they are optional. for name in read_named_args: if name not in node.argument_names: continue arg = node.arguments[node.argument_names.index(name)] - _add_read_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READ) for name in write_named_args: if name not in node.argument_names: continue arg = node.arguments[node.argument_names.index(name)] - _add_write_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.WRITE) for name in constant_named_args: if name not in node.argument_names: continue arg = node.arguments[node.argument_names.index(name)] - _add_constant_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.CONSTANT) for name in inquiry_named_args: if name not in node.argument_names: continue arg = node.arguments[node.argument_names.index(name)] - _add_inquiry_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.INQUIRY) for name in readwrite_named_args: if name not in node.argument_names: continue arg = node.arguments[node.argument_names.index(name)] - _add_readwrite_argument(arg, reference_accesses) + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READWRITE) return reference_accesses 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 index 0fcc83d823..ae11a9894d 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_reference_accesses_test.py @@ -53,11 +53,7 @@ from psyclone.psyir.nodes.intrinsic_call import ( IntrinsicCall, _reference_accesses_all_reads_with_optional_kind, - _add_read_argument, - _add_write_argument, - _add_readwrite_argument, - _add_constant_argument, - _add_inquiry_argument, + _add_argument_of_access_type, _compute_reference_accesses, ) from psyclone.psyir.symbols import ( @@ -68,13 +64,13 @@ ) -def test_add_read_argument(fortran_reader): - """ Test the _add_read_argument helper function.""" +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_read_argument(ref, vam) + _add_argument_of_access_type(ref, vam, AccessType.READ) sig, _ = ref.get_signature_and_indices() assert len(vam) == 1 @@ -84,7 +80,7 @@ def test_add_read_argument(fortran_reader): # Test we get expected behaviour for a Literal input. vam = VariablesAccessMap() lit = Literal("1", INTEGER_TYPE) - _add_read_argument(lit, vam) + _add_argument_of_access_type(lit, vam, AccessType.READ) assert len(vam) == 0 # Test we get expected behaviour for a Binop with 2 References. @@ -96,7 +92,7 @@ def test_add_read_argument(fortran_reader): ref1, ref2 ) vam = VariablesAccessMap() - _add_read_argument(binop, vam) + _add_argument_of_access_type(binop, vam, AccessType.READ) assert len(vam) == 2 sig, _ = ref1.get_signature_and_indices() assert len(vam[sig]) == 1 @@ -111,7 +107,7 @@ def test_add_read_argument(fortran_reader): ref3 = Reference(symbol2) ref = ArrayReference.create(symbol, [ref3]) vam = VariablesAccessMap() - _add_read_argument(ref, vam) + _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 @@ -131,7 +127,7 @@ def test_add_read_argument(fortran_reader): psyir = fortran_reader.psyir_from_source(code) intrinsic = psyir.walk(IntrinsicCall)[0] vam = VariablesAccessMap() - _add_read_argument(intrinsic.arguments[1], vam) + _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 @@ -150,13 +146,13 @@ def test_add_read_argument(fortran_reader): assert vam[sigs[4]][0].access_type == AccessType.CONSTANT -def test_add_write_argument(fortran_reader): - """ Test the _add_write_argument helper function.""" +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_write_argument(ref, vam) + _add_argument_of_access_type(ref, vam, AccessType.WRITE) sig, _ = ref.get_signature_and_indices() assert len(vam) == 1 @@ -166,7 +162,7 @@ def test_add_write_argument(fortran_reader): symbol = DataSymbol("c", ArrayType(INTEGER_TYPE, [2])) aref = ArrayReference.create(symbol, [ref]) vam = VariablesAccessMap() - _add_write_argument(aref, vam) + _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 @@ -192,7 +188,9 @@ def test_add_write_argument(fortran_reader): [arg.copy() for arg in call.arguments] ) vam = VariablesAccessMap() - _add_write_argument(intrinsic.arguments[0], vam) + _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 @@ -208,13 +206,14 @@ def test_add_write_argument(fortran_reader): assert vam[sigs[3]][0].access_type == AccessType.CONSTANT -def test_add_readwrite_argument(): - """ Test the _add_readwrite_argument helper function.""" +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_readwrite_argument(ref, vam) + _add_argument_of_access_type(ref, vam, AccessType.READWRITE) sig, _ = ref.get_signature_and_indices() assert len(vam) == 1 @@ -224,7 +223,7 @@ def test_add_readwrite_argument(): symbol = DataSymbol("c", ArrayType(INTEGER_TYPE, [2])) aref = ArrayReference.create(symbol, [ref]) vam = VariablesAccessMap() - _add_readwrite_argument(aref, vam) + _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 @@ -233,13 +232,14 @@ def test_add_readwrite_argument(): assert vam[sig][0].access_type == AccessType.READ -def test_add_constant_argument(): - """ Test the _add_constant_argument helper function.""" +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_constant_argument(ref, vam) + _add_argument_of_access_type(ref, vam, AccessType.CONSTANT) sig, _ = ref.get_signature_and_indices() assert len(vam) == 1 @@ -249,16 +249,17 @@ def test_add_constant_argument(): # Test we skip for a Literal vam = VariablesAccessMap() lit = Literal("1", INTEGER_TYPE) - _add_constant_argument(lit, vam) + _add_argument_of_access_type(lit, vam, AccessType.CONSTANT) assert len(vam) == 0 -def test_add_inquiry_argument(): - """ Test the _add_inquiry_argument helper function.""" +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_inquiry_argument(ref, vam) + _add_argument_of_access_type(ref, vam, AccessType.INQUIRY) sig, _ = ref.get_signature_and_indices() assert len(vam) == 1 @@ -268,13 +269,13 @@ def test_add_inquiry_argument(): # Test we skip for a Literal vam = VariablesAccessMap() lit = Literal("1", INTEGER_TYPE) - _add_inquiry_argument(lit, vam) + _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_inquiry_argument(aref, vam) + _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 From 6191022c0aca700275e6ca5d5b928c55b5671a83 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 30 Jan 2026 15:17:46 +0000 Subject: [PATCH 40/41] Rewrite of argument ordering in the variable access map to match argument ordering --- src/psyclone/psyir/nodes/intrinsic_call.py | 72 +++++++++------------- 1 file changed, 28 insertions(+), 44 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index d351346f66..620efa9119 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -142,65 +142,49 @@ def _compute_reference_accesses( :returns: the reference accesses of node. """ reference_accesses = VariablesAccessMap() - # For indices, we only apply them if there is no argument name, othrwise - # it should be handled by the argument names. - for ind in read_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] + 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) - for ind in write_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] + continue + if ind in write_indices: _add_argument_of_access_type(arg, reference_accesses, AccessType.WRITE) - for ind in readwrite_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] + continue + if ind in readwrite_indices: _add_argument_of_access_type(arg, reference_accesses, AccessType.READWRITE) - for ind in constant_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] + continue + if ind in constant_indices: _add_argument_of_access_type(arg, reference_accesses, AccessType.CONSTANT) - for ind in inquiry_indices: - if ind < len(node.arguments) and node.argument_names[ind] is None: - arg = node.arguments[ind] + continue + if ind in inquiry_indices: _add_argument_of_access_type(arg, reference_accesses, AccessType.INQUIRY) - # For each named argument provided, we check if they are defined - # for the given intrinsicCall as they are optional. - for name in read_named_args: - if name not in node.argument_names: continue - arg = node.arguments[node.argument_names.index(name)] - _add_argument_of_access_type(arg, reference_accesses, - AccessType.READ) - for name in write_named_args: - if name not in node.argument_names: + if node.argument_names[ind] in read_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.READ) continue - arg = node.arguments[node.argument_names.index(name)] - _add_argument_of_access_type(arg, reference_accesses, - AccessType.WRITE) - for name in constant_named_args: - if name not in node.argument_names: + if node.argument_names[ind] in write_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.WRITE) continue - arg = node.arguments[node.argument_names.index(name)] - _add_argument_of_access_type(arg, reference_accesses, - AccessType.CONSTANT) - for name in inquiry_named_args: - if name not in node.argument_names: + if node.argument_names[ind] in constant_named_args: + _add_argument_of_access_type(arg, reference_accesses, + AccessType.CONSTANT) continue - arg = node.arguments[node.argument_names.index(name)] - _add_argument_of_access_type(arg, reference_accesses, - AccessType.INQUIRY) - for name in readwrite_named_args: - if name not in node.argument_names: + 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 - arg = node.arguments[node.argument_names.index(name)] - _add_argument_of_access_type(arg, reference_accesses, - AccessType.READWRITE) return reference_accesses From 04c9602881697b711e8a28a7c1d2e1a3c9b949d4 Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Fri, 30 Jan 2026 15:43:41 +0000 Subject: [PATCH 41/41] Fixed access_sequence coverage --- src/psyclone/core/access_sequence.py | 4 +++- src/psyclone/tests/core/access_sequence_test.py | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/psyclone/core/access_sequence.py b/src/psyclone/core/access_sequence.py index 74f7484faf..2bb9c3a4ef 100644 --- a/src/psyclone/core/access_sequence.py +++ b/src/psyclone/core/access_sequence.py @@ -113,7 +113,9 @@ 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)}'") + raise TypeError( + f"Expected AccessType but got '{type(value).__name__}'." + ) self._access_type = value def is_any_write(self) -> bool: diff --git a/src/psyclone/tests/core/access_sequence_test.py b/src/psyclone/tests/core/access_sequence_test.py index d6c9f4bbd2..6d21407b26 100644 --- a/src/psyclone/tests/core/access_sequence_test.py +++ b/src/psyclone/tests/core/access_sequence_test.py @@ -70,6 +70,10 @@ def test_access_info() -> None: 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. '''