Source code for psyclone.psyir.nodes.intrinsic_call

# -----------------------------------------------------------------------------
# BSD 3-Clause License
#
# Copyright (c) 2022-2026, Science and Technology Facilities Council.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------
# Author: A. 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."""

from __future__ import annotations

from collections import namedtuple
from collections.abc import Iterable
from enum import Enum
from typing import List, Tuple, Callable, Union

from psyclone.core import AccessType, VariablesAccessMap
from psyclone.errors import InternalError
from psyclone.psyir.nodes.call import Call
from psyclone.psyir.nodes.datanode import DataNode
from psyclone.psyir.nodes.literal import Literal
from psyclone.psyir.nodes.reference import Reference
from psyclone.psyir.symbols import IntrinsicSymbol, Symbol
from psyclone.psyir.symbols.datatypes import (
    DataType,
    ArrayType,
    ScalarType,
    UnresolvedType,
    UnsupportedFortranType,
    NoType,
)

# 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",
)

# 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. If max_count is not None, then arg_names
# will contain a list of the argument names of the required arguments, in
# the order defined by the standard. If max_count is None, arg_names will
# be a tuple containing None to ensure the argument name computation logic
# still works.
ArgDesc = namedtuple('ArgDesc', 'min_count max_count types arg_names')


def _add_argument_of_access_type(
    argument: DataNode, var_acc_map: VariablesAccessMap,
    access_type: AccessType
) -> None:
    '''
    Adds an argument to the provided VariablesAccessMap with
    the provided access_type

    :param argument: The argument to add to the VariablesAccessMap.
    :param var_acc_map: The VariablesAccesMap to populate.
    :param access_type: The access type to use for the input argument.
    '''
    accesses = argument.reference_accesses()
    if isinstance(argument, Reference):
        sig, _ = argument.get_signature_and_indices()
        accesses[sig][-1].access_type = access_type
    var_acc_map.update(accesses)


def _compute_reference_accesses(
    node: "IntrinsicCall",
    read_named_args: Iterable[str] = (),
    write_named_args: Iterable[str] = (),
    readwrite_named_args: Iterable[str] = (),
    constant_named_args: Iterable[str] = (),
    inquiry_named_args: Iterable[str] = (),
    default_access: AccessType = AccessType.READ,
) -> VariablesAccessMap:
    """General helper function for creating the reference_accesses for a
    general IntrinsicCall.

    :param node: the IntrinsicCall whose reference_accesses to compute.
    :param read_named_args: a list of named arguments that are read accesses.
    :param write_named_args: a list of named arguments that are write
        accesses.
    :param constant_named_args: a list of named arguments that are typeinfo
        accesses.
    :param inquiry_named_args: a list of named arguments that are inquiry
        accesses.
    :param default_access: the access type for all arguments that are not
        covered by the other argument sets.

    :returns: the reference accesses of node.
    """
    reference_accesses = VariablesAccessMap()
    for ind, arg in enumerate(node.arguments):
        if node.argument_names[ind] in read_named_args:
            _add_argument_of_access_type(arg, reference_accesses,
                                         AccessType.READ)
            continue
        if node.argument_names[ind] in write_named_args:
            _add_argument_of_access_type(arg, reference_accesses,
                                         AccessType.WRITE)
            continue
        if node.argument_names[ind] in constant_named_args:
            _add_argument_of_access_type(arg, reference_accesses,
                                         AccessType.CONSTANT)
            continue
        if node.argument_names[ind] in inquiry_named_args:
            _add_argument_of_access_type(arg, reference_accesses,
                                         AccessType.INQUIRY)
            continue
        if node.argument_names[ind] in readwrite_named_args:
            _add_argument_of_access_type(arg, reference_accesses,
                                         AccessType.READWRITE)
            continue
        # Any remaining access has default provided.
        _add_argument_of_access_type(arg, reference_accesses,
                                     default_access)

    return reference_accesses


def _type_of_arg_with_rank_minus_one(
        arg: Reference, scalar_type: ScalarType
) -> Union[ScalarType, ArrayType]:
    '''
    Returns a DataType with with the type of the provided scalar_type
    with one rank less than the input arg. If arg is an array of rank 1,
    scalar_type is returned instead.

    :param arg: The argument to base the resultant type on.
    :param scalar_type: The ScalarType of the resultant type.

    :returns: A datatype with the provided scalar_type and rank 1 less than
              arg. If arg has rank 1 the scalar_type is returned.

    '''
    shape = arg.datatype.shape
    if len(shape) == 1:
        return scalar_type
    new_shape = [ArrayType.Extent.DEFERRED] * (len(shape) - 1)
    return ArrayType(scalar_type, new_shape)


def _type_of_named_argument(node: IntrinsicCall,
                            argument_name: str) -> DataType:
    """Helper function for the common IntrinsicCall case where
    the return type matches exactly the datatype of the
    argument with the provided argument_name.

    :param node: The IntrinsicCall whose return type to compute.
    :param argument_name: The name of the argument whose datatype to return.

    :returns: the datatype of the named argument of the IntrinsicCall.
    """
    return node.argument_by_name(argument_name).datatype


def _type_of_named_arg_with_optional_kind_and_dim(
        node: IntrinsicCall, arg_name: str
) -> DataType:
    """Helper function for IntrinsicCalls like MAXLOC where they have optional
    Kind and Dim options but the intrinsic type is that of the argument with
    the provided arg_name.

    :param node: The IntrinsicCall whose return type to compute.
    :param arg_name: The name of the argument that provides the intrinsic
                     type.

    :returns: the computed datatype for the IntrinsicCall.
    """
    arg = node.argument_by_name(arg_name)
    if "kind" in node.argument_names:
        dtype = ScalarType(
            arg.datatype.intrinsic,
            node.argument_by_name("kind").copy(),
        )
    else:
        # PSyclone has the UNDEFINED Precision as the default kind for all
        # supported inbuilt datatypes.
        dtype = ScalarType(
            arg.datatype.intrinsic,
            ScalarType.Precision.UNDEFINED,
        )
    # If "dim" argument isn't present then the result is an array of the same
    # dimension as the arg_name argument.
    if "dim" not in node.argument_names:
        return ArrayType(
            dtype,
            [
                Literal(
                    str(len(
                        arg.datatype.shape)),
                    ScalarType.integer_type(),
                ),
            ],
        )
    # Always have dim argument from here.
    return _type_of_arg_with_rank_minus_one(arg, dtype)


def _type_of_named_arg_accounting_for_dim_arg(
        node: IntrinsicCall, argument_name: str,
) -> DataType:
    """Helper function for the common IntrinsicCall case where the
    return type is the same as the given named argument. If intrinsiccall
    has no 'dim' argument, it returns its elemental type, but if 'dim'
    exists, it will be the given named argument's rank minus one.

    :param node: the IntrinsicCall whose return type to compute.
    :param argument_name: the name of the argument whose type to use.

    :returns: the computed datatype for the IntrinsicCall.
    """
    arg = node.argument_by_name(argument_name)
    arg_dt = arg.datatype
    if (
        not isinstance(arg_dt, ArrayType) or
        not isinstance(arg_dt.elemental_type, ScalarType) or
        not isinstance(arg_dt.elemental_type.intrinsic, ScalarType.Intrinsic)
    ):
        return UnresolvedType()
    dtype = arg_dt.elemental_type
    # If dim is not present, return the same datatype
    if "dim" not in node.argument_names:
        return dtype

    # 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.
    return _type_of_arg_with_rank_minus_one(arg, dtype)


def _type_of_scalar_with_optional_kind(
        node: IntrinsicCall, intrinsic: ScalarType.Intrinsic,
        arg_name: str
) -> DataType:
    """Helper function for the common case where the return type is a
    scalar intrinsic type with an optional kind argument.

    :param node: The IntrinsicCall whose return type to compute.
    :param intrinsic: The intrinsic type for the datatype.
    :param arg_name: The name of the optional argument to use for the kind.

    :returns: the computed datatype for the IntrinsicCall.
    """
    return (
        ScalarType(
            intrinsic,
            node.argument_by_name(arg_name).copy(),
        )
        if arg_name in node.argument_names
        # Otherwise, use the default Precision (in PSyclone this is the
        # UNDEFINED precision)
        else ScalarType(intrinsic, ScalarType.Precision.UNDEFINED)
    )


def _type_of_intrinsic_with_argname_kind_and_optional_dim(
        node: IntrinsicCall, intrinsic: ScalarType.Intrinsic,
        array_arg_name: str, kind_arg_name: str) -> DataType:
    """Helper function for a datatype of type intrinsic with optional dim and
    optional arg_name kind option. If the dim argument exists, then the
    dimensionality of the result is based on the argument that has the
    array_arg_name.

    :param node: The IntrinsicCall whose return type to compute.
    :param intrinsic: The intrinsic type of the resultant datatype.
    :param array_arg_name: The name of the array type to use to compute
                           dimensionality if dim is requested.
    :param kind_arg_name: The name of the optional argument to base the
                          precision of the resultant datatype on.

    :returns: the computed datatype for the IntrinsicCall.
    """
    dtype = ScalarType(
        intrinsic,
        (
            ScalarType.Precision.UNDEFINED
            if kind_arg_name not in node.argument_names
            else node.argument_by_name(kind_arg_name).copy()
        ),
    )
    # If dim is not present then we return a scalar.
    if "dim" not in node.argument_names:
        return dtype
    # 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.argument_by_name(array_arg_name)
    return _type_of_arg_with_rank_minus_one(arg, dtype)


def _type_of_intrinsic_with_precision_of_named_arg(
        node: IntrinsicCall, intrinsic: ScalarType.Intrinsic,
        argument_name: str
) -> DataType:
    """Helper function for the common IntrinsicCall case where the
    return type is a scalar of the type of the supplied intrinsic,
    with the kind of the first argument.

    :param node: The IntrinsicCall whose return type to compute.
    :param intrinsic: The datatype intrinsic type to use.
    :param argument_name: The name of the argument to use for the precision
                          of the datatype.

    :returns: the computed datatype for the IntrinsicCall.
    """
    return ScalarType(
        intrinsic, node.argument_by_name(argument_name).datatype.precision
    )


def _findloc_return_type(node: IntrinsicCall) -> DataType:
    """Helper function for the FINDLOC case.

    The datatype of FINDLOC is a rank-one array of dimension equal to
    the "array" named argument, unless dim is present in which case
    the datatype is an N-1 dimension array.
    If the optional argument
    "kind" is present, then the precision of the resulting datatype
    is equal to the kind argument.

    :param node: The IntrinsicCall whose return type to compute.

    :returns: the computed datatype for the IntrinsicCall.
    """
    if "kind" in node.argument_names:
        dtype = ScalarType(
            node.argument_by_name("array").datatype.intrinsic,
            node.argument_by_name("kind").copy(),
        )
    else:
        dtype = node.argument_by_name("array").datatype.copy()
    # If dim argument is given.
    if "dim" in node.argument_names:
        arg = node.argument_by_name("array")
        return _type_of_arg_with_rank_minus_one(arg, dtype)
    # Otherwise return an array with same rank as the "array"
    # argument.
    return ArrayType(
        dtype,
        [
            Literal(
                str(len(node.argument_by_name(
                            "array"
                        ).datatype.shape)),
                ScalarType.integer_type(),
            ),
        ],
    )


def _int_return_type(node: IntrinsicCall) -> DataType:
    """Helper function for the INT case.

    The resulting datatype is an scalar integer of default kind
    (unless the "kind" argument is provided, in which case the kind
    specified by the argument) if "a" is a scalar.

    If "a" is an array, then it is an ArrayType of the same size as
    the input, with the datatype of the scalar type specified in
    the previous paragraph.

    :param node: The IntrinsicCall whose return type to compute.

    :returns: the computed datatype for the IntrinsicCall.
    """
    if "kind" in node.argument_names:
        dtype = ScalarType(
            ScalarType.Intrinsic.INTEGER,
            node.argument_by_name("kind").copy(),
        )
    else:
        dtype = ScalarType.integer_type()

    if not isinstance(node.argument_by_name("a").datatype, ArrayType):
        return dtype
    return ArrayType(
        dtype,
        [
            index.copy()
            for index in node.argument_by_name("a").datatype.shape
        ],
    )


def _get_bound_function_return_type(node: IntrinsicCall) -> DataType:
    """Helper function for the return types of functions like LBOUND and
    LCOBOUND etc.

    The return type is of type integer and of the kind specified by the
    "kind" argument if present, or the default
    (ScalarType.Precision.UNDEFINED) otherwise.
    If the "dim" argument is present, then the result is that ScalarType.
    Otherwise, it's an array of that ScalarType with extent equal to the
    rank of the "array" argument.

    :param node: The IntrinsicCall whose return type to compute.

    :returns: the computed datatype for the IntrinsicCall.
    """
    if "kind" in node.argument_names:
        dtype = ScalarType(
            ScalarType.Intrinsic.INTEGER,
            node.argument_by_name("kind").copy(),
        )
    else:
        dtype = ScalarType.integer_type()
    # If "dim" is in the arguments, then return a Scalar.
    if "dim" in node.argument_names:
        return dtype
    # Otherwise return an array with rank equal to the "array" argument.
    return ArrayType(
        dtype,
        [
            Literal(
                str(len(node.argument_by_name("array").datatype.shape)),
                ScalarType.integer_type()
            ),
        ],
    )


def _matmul_return_type(node: IntrinsicCall) -> DataType:
    """Helper function for the return type of MATMUL.

    If matrix_a is a vector and matrix_b is a matrix, then the
    result is an array of shape of the first dimension of matrix_b.
    If matrix_b is a vector and matrix_a is a matrix, then the
    result is an array of shape of the first dimension of matrix_a.
    If matrix_a and matrix_b are both matrices, then the result
    is an array of shape [matrix_a dim 1, matrix_b dim 2].

    :param node: The IntrinsicCall whose return type to compute.

    :returns: the computed datatype for the IntrinsicCall.
    """
    # pylint: disable=import-outside-toplevel
    from psyclone.psyir.tools.type_info_computation import (
        compute_scalar_type
    )
    argtype1 = node.argument_by_name("matrix_a").datatype
    argtype2 = node.argument_by_name("matrix_b").datatype
    shape1 = argtype1.shape
    shape2 = argtype2.shape
    # Create scalar versions of the datatypes to compute the datatype
    # of the result.
    stype1 = ScalarType(argtype1.intrinsic, argtype1.precision)
    stype2 = ScalarType(argtype2.intrinsic, argtype2.precision)
    stype = compute_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
    # Vector-matrix case.
    if len(shape1) == 1:
        extent = IntrinsicCall.create(
            IntrinsicCall.Intrinsic.SIZE,
            [node.argument_by_name("matrix_b").copy(),
             ("dim", Literal("1", ScalarType.integer_type()))])
        shape = [extent]
    # Matrix-vector case.
    elif len(shape2) == 1:
        extent = IntrinsicCall.create(
            IntrinsicCall.Intrinsic.SIZE,
            [node.argument_by_name("matrix_a").copy(),
             ("dim", Literal("1", ScalarType.integer_type()))])
        shape = [extent]
    else:
        # matrix-matrix. Result is size(arg0, 1) x size(arg1, 2)
        extent1 = IntrinsicCall.create(
            IntrinsicCall.Intrinsic.SIZE,
            [node.argument_by_name("matrix_a").copy(),
             ("dim", Literal("1", ScalarType.integer_type()))])
        extent2 = IntrinsicCall.create(
            IntrinsicCall.Intrinsic.SIZE,
            [node.argument_by_name("matrix_b").copy(),
             ("dim", Literal("2", ScalarType.integer_type()))])
        shape = [extent1, extent2]
    return ArrayType(stype, shape)


def _dot_product_return_type(node: IntrinsicCall) -> DataType:
    """Helper value for DOT_PRODUCT intrinsic return type.

    The result is a scalar with the promoted Fortran type computed by
    compute_scalar_type.

    :param node: The IntrinsicCall whose return type to compute.

    :returns: the computed datatype for the IntrinsicCall.
    """
    # pylint: disable=import-outside-toplevel
    from psyclone.psyir.tools.type_info_computation import (
        compute_scalar_type
    )
    veca_datatype = node.argument_by_name("vector_a").datatype.elemental_type
    vecb_datatype = node.argument_by_name("vector_b").datatype.elemental_type
    return compute_scalar_type(
        [ScalarType(
            veca_datatype.intrinsic, veca_datatype.precision
         ),
         ScalarType(
            vecb_datatype.intrinsic, vecb_datatype.precision
         ),
         ]
    )


[docs] class IntrinsicCall(Call): """Node representing a call to an intrinsic routine (function or subroutine). This can be found as a standalone statement or an expression. :param intrinsic: the type of Intrinsic being created. :type intrinsic: py:class:`psyclone.psyir.IntrinsicCall.Intrinsic` :param kwargs: additional keyword arguments provided to the PSyIR node. :type kwargs: unwrapped dict. :raises TypeError: if the 'intrinsic' argument is not an Intrinsic type. """ # Textual description of the node. _children_valid_format = "[DataNode]*" _text_name = "IntrinsicCall" _colour = "cyan" #: The type of Symbol this Call must refer to. Used for type checking in #: the constructor (of the parent class). _symbol_type = IntrinsicSymbol
[docs] class Intrinsic(IAttr, Enum): """Enum of all intrinsics with their attributes as values using the IAttr namedtuple format: NAME = IAttr(name, is_pure, is_elemental, is_inquiry, 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 not be guaranteed. All argument names (i.e. required_args.arg_names and optional_args) should be lower case. """ # Fortran special-case statements (technically not Fortran intrinsics # but in PSyIR they are represented as Intrinsics) ALLOCATE = IAttr( name="ALLOCATE", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=None, types=Reference, arg_names=((None,),)), optional_args={ "mold": Reference, "source": Reference, "stat": Reference, "errmsg": Reference, }, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["mold", "source"], write_named_args=["stat", "errmsg"], default_access=AccessType.WRITE ) ), ) DEALLOCATE = IAttr( name="DEALLOCATE", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=None, types=Reference, arg_names=((None,),)), optional_args={"stat": Reference}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_args=["stat"], default_access=AccessType.WRITE ) ), ) NULLIFY = IAttr( name="NULLIFY", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=None, types=Reference, arg_names=((None,),)), optional_args={}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, default_access=AccessType.WRITE ) ), ) # Fortran Intrinsics (from Fortran 2018 standard table 16.1) ABS = IAttr( name="ABS", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={}, # TODO 1590 Complex to real conversion unsupported. return_type=lambda node: _type_of_named_argument(node, "a"), reference_accesses=lambda node: ( _compute_reference_accesses(node) ), ) ACHAR = IAttr( name="ACHAR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={"kind": DataNode}, return_type=ScalarType.character_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) ACOS = IAttr( name="ACOS", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ACOSH = IAttr( name="ACOSH", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ADJUSTL = IAttr( name="ADJUSTL", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("string",),)), optional_args={}, # Returned string is of the same length as the input (trailing # spaces are added as needed). return_type=lambda node: _type_of_named_argument(node, "string"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ADJUSTR = IAttr( name="ADJUSTR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("string",),)), optional_args={}, # Returned string is of the same length as the input (leading # spaces are added as needed). return_type=lambda node: _type_of_named_argument(node, "string"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) AIMAG = IAttr( name="AIMAG", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("z",),)), optional_args={}, # TODO #1590 Complex numbers' precision unsupported. return_type=lambda node: UnsupportedFortranType(""), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) AINT = IAttr( name="AINT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=lambda node: ScalarType( ScalarType.Intrinsic.REAL, ( node.argument_by_name("kind").copy() if "kind" in node.argument_names else node.argument_by_name("a").datatype.precision ), ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"], ) ), ) ALL = IAttr( name="ALL", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("mask",),)), optional_args={"dim": DataNode}, return_type=( lambda node: _type_of_named_arg_accounting_for_dim_arg( node, "mask" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ALLOCATED = IAttr( name="ALLOCATED", is_pure=True, is_elemental=False, is_inquiry=True, # Argname of allocated depends on the input. required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("",),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, default_access=AccessType.INQUIRY ) ), ) ANINT = IAttr( name="ANINT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=lambda node: ScalarType( ScalarType.Intrinsic.REAL, ( node.argument_by_name("kind").copy() if "kind" in node.argument_names else node.argument_by_name("a").datatype.precision ), ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"], ) ), ) ANY = IAttr( name="ANY", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("mask",),)), optional_args={"dim": DataNode}, return_type=( lambda node: _type_of_named_arg_accounting_for_dim_arg( node, "mask" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ASIN = IAttr( name="ASIN", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ASINH = IAttr( name="ASINH", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ASSOCIATED = IAttr( name="ASSOCIATED", is_pure=False, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("pointer",),)), optional_args={"target": DataNode}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["pointer", "target"], ) ), ) ATAN = IAttr( name="ATAN", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=(("x",), ("y", "x"))), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ATAN2 = IAttr( name="ATAN2", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("y", "x"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "y"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ATANH = IAttr( name="ATANH", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ATOMIC_ADD = IAttr( name="ATOMIC_ADD", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], ) ), ) ATOMIC_AND = IAttr( name="ATOMIC_AND", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], ) ), ) ATOMIC_CAS = IAttr( name="ATOMIC_CAS", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=4, max_count=4, types=DataNode, arg_names=( ("atom", "old", "compare", "new"), ) ), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], write_named_args=["old", "stat"], read_named_args=["new", "compare"], ) ), ) ATOMIC_DEFINE = IAttr( name="ATOMIC_DEFINE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], ) ), ) ATOMIC_FETCH_ADD = IAttr( name="ATOMIC_FETCH_ADD", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=( ("atom", "value", "old"), ) ), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], ) ), ) ATOMIC_FETCH_AND = IAttr( name="ATOMIC_FETCH_AND", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=( ("atom", "value", "old"), ) ), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], ) ), ) ATOMIC_FETCH_OR = IAttr( name="ATOMIC_FETCH_OR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=( ("atom", "value", "old"), ) ), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], ) ), ) ATOMIC_FETCH_XOR = IAttr( name="ATOMIC_FETCH_XOR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=( ("atom", "value", "old"), ) ), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["old", "stat"], ) ), ) ATOMIC_OR = IAttr( name="ATOMIC_OR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], ) ), ) ATOMIC_REF = IAttr( name="ATOMIC_REF", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("value", "atom"),)), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_args=["value", "stat"], read_named_args=["atom"], ) ), ) ATOMIC_XOR = IAttr( name="ATOMIC_XOR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("atom", "value"),)), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["atom"], read_named_args=["value"], write_named_args=["stat"], ) ), ) BESSEL_J0 = IAttr( name="BESSEL_J0", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BESSEL_J1 = IAttr( name="BESSEL_J1", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BESSEL_JN = IAttr( name="BESSEL_JN", is_pure=True, # TODO 3141 The elemental status is dependent on the # structure of the IntrinsicCall. is_elemental=None, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=3, types=DataNode, arg_names=( ("n", "x"), ("n1", "n2", "x"), ) ), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BESSEL_Y0 = IAttr( name="BESSEL_Y0", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BESSEL_Y1 = IAttr( name="BESSEL_Y1", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BESSEL_YN = IAttr( name="BESSEL_YN", is_pure=True, # TODO 3141 The elemental status is dependent on the # structure of the IntrinsicCall. is_elemental=None, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=3, types=DataNode, arg_names=( ("n", "x"), ("n1", "n2", "x"), ) ), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BGE = IAttr( name="BGE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "j"),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BGT = IAttr( name="BGT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "j"),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BIT_SIZE = IAttr( name="BIT_SIZE", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["i"], ) ), ) BLE = IAttr( name="BLE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "j"),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BLT = IAttr( name="BLT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "j"),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) BTEST = IAttr( name="BTEST", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "pos"),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) CEILING = IAttr( name="CEILING", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) CHAR = IAttr( name="CHAR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={"kind": DataNode}, return_type=ScalarType.character_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) CMPLX = IAttr( name="CMPLX", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={"y": DataNode, "kind": DataNode}, # TODO #1590 Complex numbers unsupported. return_type=lambda node: UnsupportedFortranType(""), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) CO_BROADCAST = IAttr( name="CO_BROADCAST", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=( ("a", "source_image"), ) ), optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["a"], read_named_args=["source_image"], write_named_args=["stat", "errmsg"], ) ), ) CO_MAX = IAttr( name="CO_MAX", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], ) ), ) CO_MIN = IAttr( name="CO_MIN", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], ) ), ) CO_REDUCE = IAttr( name="CO_REDUCE", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=( ("a", "operation"), ) ), optional_args={"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], inquiry_args=["operation"], ) ), ) CO_SUM = IAttr( name="CO_SUM", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"result_image": DataNode, "stat": DataNode, "errmsg": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, readwrite_named_args=["a"], read_named_args=["result_image"], write_named_args=["stat", "errmsg"], ) ), ) COMMAND_ARGUMENT_COUNT = IAttr( name="COMMAND_ARGUMENT_COUNT", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=None, arg_names=()), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: VariablesAccessMap(), ) CONJG = IAttr( name="CONJG", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("z",),)), optional_args={}, # TODO #1590 Complex numbers unsupported. return_type=lambda node: UnsupportedFortranType(""), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) COS = IAttr( name="COS", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) COSH = IAttr( name="COSH", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) COSHAPE = IAttr( name="COSHAPE", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("coarray",),)), optional_args={"kind": DataNode}, return_type=lambda node: ArrayType( ScalarType( ScalarType.Intrinsic.INTEGER, ( node.argument_by_name("coarray").datatype.precision if "kind" not in node.argument_names else node.argument_by_name("kind").copy() ), ), [ index.copy() for index in node.argument_by_name( "coarray" ).datatype.shape ], ), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_arguments=["coarray"], constant_named_arguments=["kind"], ) ), ) COUNT = IAttr( name="COUNT", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("mask",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=lambda node: _type_of_intrinsic_with_argname_kind_and_optional_dim( node, ScalarType.Intrinsic.INTEGER, "mask", "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) CPU_TIME = IAttr( name="CPU_TIME", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("time",),)), optional_args={}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_arguments=["time"], ) ), ) CSHIFT = IAttr( name="CSHIFT", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("array", "shift"),)), optional_args={"dim": DataNode}, return_type=lambda node: _type_of_named_argument(node, "array"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) DATE_AND_TIME = IAttr( name="DATE_AND_TIME", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={ "date": DataNode, "time": DataNode, "zone": DataNode, "values": DataNode, }, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_args=["date", "time", "zone", "values"], ) ), ) DBLE = IAttr( name="DBLE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={}, return_type=ScalarType.real_double_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) DIGITS = IAttr( name="DIGITS", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) DIM = IAttr( name="DIM", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("x", "y"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) DOT_PRODUCT = IAttr( name="DOT_PRODUCT", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("vector_a", "vector_b"),) ), optional_args={}, return_type=lambda node: _dot_product_return_type( node ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) DPROD = IAttr( name="DPROD", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("x", "y"),)), optional_args={}, return_type=ScalarType.real8_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) DSHIFTL = IAttr( name="DSHIFTL", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=(("i", "j", "shift"),)), optional_args={}, return_type=lambda node: (_type_of_named_argument( node, "j" if isinstance(node.argument_by_name("i"), Literal) else "i" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) DSHIFTR = IAttr( name="DSHIFTR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=(("i", "j", "shift"),)), optional_args={}, return_type=lambda node: (_type_of_named_argument( node, "j" if isinstance(node.argument_by_name("i"), Literal) else "i" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) EOSHIFT = IAttr( name="EOSHIFT", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("array", "shift"),)), optional_args={"boundary": DataNode, "dim": DataNode}, return_type=lambda node: _type_of_named_argument(node, "array"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) EPSILON = IAttr( name="EPSILON", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) ERF = IAttr( name="ERF", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ERFC = IAttr( name="ERFC", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ERFC_SCALED = IAttr( name="ERFC_SCALED", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.REAL, "x" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) EVENT_QUERY = IAttr( name="EVENT_QUERY", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("event", "count"),)), optional_args={"stat": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["event"], write_named_args=["count", "stat"], ) ), ) EXECUTE_COMMAND_LINE = IAttr( name="EXECUTE_COMMAND_LINE", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("command",),)), optional_args={ "wait": DataNode, "exitstat": DataNode, "cmdstat": DataNode, "cmdmsg": DataNode, }, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["command", "wait"], write_named_args=["exitstat", "cmdstat", "cmdmsg"], ) ), ) EXP = IAttr( name="EXP", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) EXPONENT = IAttr( name="EXPONENT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) EXTENDS_TYPE_OF = IAttr( name="EXTENDS_TYPE_OF", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("a", "mold"),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["a", "mold"], ) ), ) FAILED_IMAGES = IAttr( name="FAILED_IMAGES", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={"team": DataNode, "kind": DataNode}, return_type=lambda node: ArrayType( _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), [ArrayType.Extent.DEFERRED], ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) FINDLOC = IAttr( name="FINDLOC", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=3, types=DataNode, arg_names=( ("array", "value", "dim"), ("array", "value") ) ), optional_args={"mask": DataNode, "kind": DataNode, "back": DataNode}, return_type=_findloc_return_type, reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) FLOAT = IAttr( name="FLOAT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, # FLOAT is a language extension, and not all compilers # (e.g. nvfortran) can handle a keyword argument. arg_names=(("",),)), optional_args={}, return_type=ScalarType.real_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) FLOOR = IAttr( name="FLOOR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) FRACTION = IAttr( name="FRACTION", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) GAMMA = IAttr( name="GAMMA", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) GET_COMMAND = IAttr( name="GET_COMMAND", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={ "command": DataNode, "length": DataNode, "status": DataNode, "errmsg": DataNode, }, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_args=["command", "length", "status"], readwrite_named_args=["errmsg"], ) ), ) GET_COMMAND_ARGUMENT = IAttr( name="GET_COMMAND_ARGUMENT", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("number",),)), optional_args={ "value": DataNode, "length": DataNode, "status": DataNode, "errmsg": DataNode, }, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["number"], write_named_args=["value", "length", "status"], readwrite_named_args=["errmsg"], ) ), ) GET_ENVIRONMENT_VARIABLE = IAttr( name="GET_ENVIRONMENT_VARIABLE", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("name",),)), optional_args={ "value": DataNode, "length": DataNode, "status": DataNode, "trim_name": DataNode, "errmsg": DataNode, }, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["name", "trim_name"], write_named_args=["value", "length", "status"], readwrite_named_args=["errmsg"], ) ), ) GET_TEAM = IAttr( name="GET_TEAM", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={"level": DataNode}, # Unsupported return type (TEAM_TYPE from ISO_FORTRAN_ENV). return_type=lambda node: UnsupportedFortranType("TEAM_TYPE"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) HUGE = IAttr( name="HUGE", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=(Reference, Literal), arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) HYPOT = IAttr( name="HYPOT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("x", "y"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IACHAR = IAttr( name="IACHAR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("c",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) IALL = IAttr( name="IALL", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={"mask": DataNode}, return_type=lambda node: # No kind option is available, however if we provide a fake # argument name as the final parameter this function will # provide the correct result. _type_of_intrinsic_with_argname_kind_and_optional_dim( node, ScalarType.Intrinsic.INTEGER, "array", "no_kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, ) ), ) IAND = IAttr( name="IAND", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "j"),)), optional_args={}, return_type=lambda node: (_type_of_named_argument( node, "j" if isinstance(node.argument_by_name("i"), Literal) else "i" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IANY = IAttr( name="IANY", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={"mask": DataNode}, return_type=lambda node: # No kind option is available, however if we provide a fake # argument name as the final parameter this function will # provide the correct result. _type_of_intrinsic_with_argname_kind_and_optional_dim( node, ScalarType.Intrinsic.INTEGER, "array", "no_kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IBCLR = IAttr( name="IBCLR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "pos"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IBITS = IAttr( name="IBITS", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=(("i", "pos", "len"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IBSET = IAttr( name="IBSET", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "pos"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ICHAR = IAttr( name="ICHAR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("c",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) IEOR = IAttr( name="IEOR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "j"),)), optional_args={}, return_type=lambda node: (_type_of_named_argument( node, "j" if isinstance(node.argument_by_name("i"), Literal) else "i" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IMAGE_INDEX = IAttr( name="IMAGE_INDEX", is_pure=True, is_elemental=False, is_inquiry=True, # Argument names depend on input, as TEAM vs TEAM_NUMBER # are not distinguishable without context. required_args=ArgDesc( min_count=2, max_count=3, types=DataNode, arg_names=(("",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IMAGE_STATUS = IAttr( name="IMAGE_STATUS", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("image",),)), optional_args={"team": DataNode}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) INDEX = IAttr( name="INDEX", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("string", "substring"),)), optional_args={"back": DataNode, "kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) INT = IAttr( name="INT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=_int_return_type, reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) IOR = IAttr( name="IOR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "j"),)), optional_args={}, return_type=lambda node: ( _type_of_intrinsic_with_precision_of_named_arg( node, ScalarType.Intrinsic.INTEGER, "j" if isinstance(node.argument_by_name("i"), Literal) else "i" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IPARITY = IAttr( name="IPARITY", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={"mask": DataNode}, return_type=lambda node: ( _type_of_named_arg_accounting_for_dim_arg(node, "array") ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) IS_CONTIGUOUS = IAttr( name="IS_CONTIGUOUS", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("array",),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["array"], ) ), ) IS_IOSTAT_END = IAttr( name="IS_IOSTAT_END", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, ) ), ) IS_IOSTAT_EOR = IAttr( name="IS_IOSTAT_EOR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ISHFT = IAttr( name="ISHFT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) ISHFTC = IAttr( name="ISHFTC", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("i", "shift"),)), optional_args={"size": DataNode}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) KIND = IAttr( name="KIND", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) LBOUND = IAttr( name="LBOUND", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("array",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["array"], read_named_args=["dim"], constant_named_args=["kind"], ) ), ) LCOBOUND = IAttr( name="LCOBOUND", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("coarray",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["coarray"], read_named_args=["dim"], constant_named_args=["kind"], ) ), ) LEADZ = IAttr( name="LEADZ", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LEN = IAttr( name="LEN", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("string",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) LEN_TRIM = IAttr( name="LEN_TRIM", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("string",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) LGE = IAttr( name="LGE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("string_a", "string_b"),) ), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LGT = IAttr( name="LGT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("string_a", "string_b"),) ), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LLE = IAttr( name="LLE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("string_a", "string_b"),) ), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LLT = IAttr( name="LLT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("string_a", "string_b"),) ), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LOG = IAttr( name="LOG", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LOG_GAMMA = IAttr( name="LOG_GAMMA", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LOG10 = IAttr( name="LOG10", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) LOGICAL = IAttr( name="LOGICAL", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("l",),)), optional_args={"kind": DataNode}, return_type=lambda node: ( _type_of_scalar_with_optional_kind( node, node.argument_by_name("l").datatype.intrinsic, "kind", ) if "kind" in node.argument_names else _type_of_named_argument(node, "l") ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) MASKL = IAttr( name="MASKL", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) MASKR = IAttr( name="MASKR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) MATMUL = IAttr( name="MATMUL", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("matrix_a", "matrix_b"),) ), optional_args={}, return_type=_matmul_return_type, reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MAX = IAttr( name="MAX", is_pure=True, is_elemental=True, is_inquiry=False, # No upper limit on argument type so we don't store an # argument list of names. required_args=ArgDesc( min_count=2, max_count=None, types=DataNode, arg_names=((None,),)), optional_args={}, return_type=lambda node: node.arguments[0].datatype, reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MAXEXPONENT = IAttr( name="MAXEXPONENT", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) MAXLOC = IAttr( name="MAXLOC", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={ "mask": DataNode, "kind": DataNode, "back": DataNode, }, return_type=lambda node: ( _type_of_named_arg_with_optional_kind_and_dim( node, "array" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) MAXVAL = IAttr( name="MAXVAL", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={"mask": DataNode}, return_type=lambda node: ( _type_of_named_arg_accounting_for_dim_arg(node, "array") ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MERGE = IAttr( name="MERGE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=(("tsource", "fsource", "mask"),) ), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "tsource"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MERGE_BITS = IAttr( name="MERGE_BITS", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=(("i", "j", "mask"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MIN = IAttr( name="MIN", is_pure=True, is_elemental=True, is_inquiry=False, # No upper limit on argument type so we don't store an # argument list of names. required_args=ArgDesc( min_count=2, max_count=None, types=DataNode, arg_names=((None,),)), optional_args={}, return_type=lambda node: node.arguments[0].datatype, reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MINEXPONENT = IAttr( name="MINEXPONENT", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) MINLOC = IAttr( name="MINLOC", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={ "mask": DataNode, "kind": DataNode, "back": DataNode, }, return_type=lambda node: ( _type_of_named_arg_with_optional_kind_and_dim( node, "array" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) MINVAL = IAttr( name="MINVAL", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={"mask": DataNode}, return_type=lambda node: ( _type_of_named_arg_accounting_for_dim_arg(node, "array") ), reference_accesses=lambda node: ( _compute_reference_accesses( node, ) ), ) MOD = IAttr( name="MOD", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("a", "p"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "a"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MODULO = IAttr( name="MODULO", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("a", "p"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "a"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) MOVE_ALLOC = IAttr( name="MOVE_ALLOC", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("from", "to"),)), optional_args={"stat": DataNode, "errmsg": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_args=["to", "stat"], readwrite_named_args=["from", "errmsg"], ) ), ) MVBITS = IAttr( name="MVBITS", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=5, max_count=5, types=DataNode, arg_names=( ("from", "frompos", "len", "to", "topos"), ) ), optional_args={}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["from", "frompos", "len", "topos"], write_named_args=["to"], ) ), ) NEAREST = IAttr( name="NEAREST", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("x", "s"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) NEW_LINE = IAttr( name="NEW_LINE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("c"),)), optional_args={}, return_type=ScalarType.character_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["c"], ) ), ) NINT = IAttr( name="NINT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) NORM2 = IAttr( name="NORM2", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("x",), ("x", "dim") ) ), optional_args={}, # No kind on NORM2 but this function works for return type. return_type=lambda node: ( _type_of_named_arg_with_optional_kind_and_dim( node, "x" ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) NOT = IAttr( name="NOT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=lambda node: ScalarType( ScalarType.Intrinsic.INTEGER, node.argument_by_name("i").datatype.precision ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) NULL = IAttr( name="NULL", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={"mold": DataNode}, # Returns a dissociated pointed - not supported. return_type=lambda node: UnsupportedFortranType(""), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["mold"], ) ), ) NUM_IMAGES = IAttr( name="NUM_IMAGES", is_pure=True, is_elemental=False, is_inquiry=False, # Argnames depends on the input. required_args=ArgDesc( min_count=0, max_count=1, types=DataNode, arg_names=(("",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) OUT_OF_RANGE = IAttr( name="OUT_OF_RANGE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("x", "mold",),)), optional_args={"round": DataNode}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["x", "round"], constant_named_args=["mold"], ) ), ) PACK = IAttr( name="PACK", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("array", "mask"),)), optional_args={"vector": DataNode}, return_type=lambda node: ArrayType( ScalarType( node.argument_by_name("array").datatype.intrinsic, node.argument_by_name("array").datatype.precision), [ArrayType.Extent.DEFERRED] ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) PARITY = IAttr( name="PARITY", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("mask",), ("mask", "dim") ) ), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "mask"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) POPCNT = IAttr( name="POPCNT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) POPPAR = IAttr( name="POPPAR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) PRECISION = IAttr( name="PRECISION", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) PRESENT = IAttr( name="PRESENT", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["a"], ) ), ) PRODUCT = IAttr( name="PRODUCT", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={"mask": DataNode}, return_type=( lambda node: _type_of_named_arg_accounting_for_dim_arg( node, "array", ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) RADIX = IAttr( name="RADIX", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) RANDOM_INIT = IAttr( name="RANDOM_INIT", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("repeatable", "image_distinct"),) ), optional_args={}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) RANDOM_NUMBER = IAttr( name="RANDOM_NUMBER", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("harvest",),)), optional_args={}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_args=["harvest"], ) ), ) RANDOM_SEED = IAttr( name="RANDOM_SEED", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=Reference, arg_names=()), optional_args={"size": DataNode, "put": DataNode, "Get": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, read_named_args=["put"], write_named_args=["size", "get"], ) ), ) RANGE = IAttr( name="RANGE", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("x",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) RANK = IAttr( name="RANK", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("a",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["a"], ) ), ) REAL = IAttr( name="REAL", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=lambda node: ( ScalarType( ScalarType.Intrinsic.REAL, ( node.argument_by_name("kind").copy() if "kind" in node.argument_names else node.argument_by_name("a").datatype.precision ), ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) REDUCE = IAttr( name="REDUCE", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=3, types=DataNode, arg_names=( ("array", "operation"), ("array", "operation", "dim") ) ), optional_args={"mask": DataNode, "identity": DataNode, "ordered": DataNode}, return_type=lambda node: ( _type_of_named_arg_accounting_for_dim_arg(node, "array") ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) REPEAT = IAttr( name="REPEAT", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("string", "ncopies"),)), optional_args={}, return_type=ScalarType.character_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) RESHAPE = IAttr( name="RESHAPE", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("source", "shape"),)), optional_args={"pad": DataNode, "order": DataNode}, # I went with unresolved for now as the result depends on # argument 2 (even the dimensionality). return_type=lambda node: UnresolvedType(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) RRSPACING = IAttr( name="RRSPACING", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SAME_TYPE_AS = IAttr( name="SAME_TYPE_AS", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("a", "b"),)), optional_args={}, return_type=ScalarType.boolean_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["a", "b"], ) ), ) SCALE = IAttr( name="SCALE", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("x", "i"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SCAN = IAttr( name="SCAN", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("string", "set"),)), optional_args={"back": DataNode, "kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) SELECTED_CHAR_KIND = IAttr( name="SELECTED_CHAR_KIND", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("name",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SELECTED_INT_KIND = IAttr( name="SELECTED_INT_KIND", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("r",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SELECTED_REAL_KIND = IAttr( name="SELECTED_REAL_KIND", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=Reference, arg_names=()), optional_args={"p": DataNode, "r": DataNode, "radix": DataNode}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SET_EXPONENT = IAttr( name="SET_EXPONENT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("x", "i"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SHAPE = IAttr( name="SHAPE", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=Reference, arg_names=(("source",),)), 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.argument_by_name("kind").copy())), [Literal(str(len( node.argument_by_name("source").datatype.shape)), ScalarType.integer_type())]) ), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["source"], constant_named_args=["kind"], ) ), ) SHIFTA = IAttr( name="SHIFTA", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SHIFTL = IAttr( name="SHIFTL", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SHIFTR = IAttr( name="SHIFTR", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=Reference, arg_names=(("i", "shift"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "i"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SIGN = IAttr( name="SIGN", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("a", "b"),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "a"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SIN = IAttr( name="SIN", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SINH = IAttr( name="SINH", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SIZE = IAttr( name="SIZE", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("array",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["array"], read_named_args=["dim"], constant_named_args=["kind"], ) ), ) SPACING = IAttr( name="SPACING", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) SPREAD = IAttr( name="SPREAD", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=(("source", "dim", "ncopies"),) ), optional_args={}, return_type=lambda node: ArrayType( ScalarType( node.argument_by_name("source").datatype.intrinsic, node.argument_by_name("source").datatype.precision), ([ArrayType.Extent.DEFERRED] * (len(node.argument_by_name("source").datatype.shape) + 1) if isinstance(node.argument_by_name("source").datatype, ArrayType) else [ArrayType.Extent.DEFERRED]) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SQRT = IAttr( name="SQRT", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, # TODO 1590 Complex conversion unsupported. return_type=lambda node: UnsupportedFortranType(""), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) STOPPED_IMAGES = IAttr( name="STOPPED_IMAGES", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={"team": DataNode, "kind": DataNode}, return_type=lambda node: ArrayType( _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ) [ArrayType.Extent.DEFERRED] ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) STORAGE_SIZE = IAttr( name="STORAGE_SIZE", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("a",),)), optional_args={"kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["a"], constant_named_args=["kind"], ) ), ) SUM = IAttr( name="SUM", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=2, types=DataNode, arg_names=( ("array",), ("array", "dim") ) ), optional_args={"mask": DataNode}, return_type=( lambda node: _type_of_named_arg_accounting_for_dim_arg( node, "array", ) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) SYSTEM_CLOCK = IAttr( name="SYSTEM_CLOCK", is_pure=False, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={"count": DataNode, "count_rate": DataNode, "count_max": DataNode}, return_type=None, reference_accesses=lambda node: ( _compute_reference_accesses( node, write_named_args=[ "count", "count_rate", "count_max", ], ) ), ) TAN = IAttr( name="TAN", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) TANH = IAttr( name="TANH", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("x",),)), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) TEAM_NUMBER = IAttr( name="TEAM_NUMBER", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=0, types=DataNode, arg_names=()), optional_args={"team": DataNode}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) THIS_IMAGE = IAttr( name="THIS_IMAGE", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=0, max_count=2, types=DataNode, arg_names=( (), ("coarray",), ("coarray", "dim") ) ), optional_args={"team": DataNode}, # Support for this is not currently implemented, however it is # an integer or array of integer's depending on arguments, so # could be added later. See # https://gcc.gnu.org/onlinedocs/gfortran/THIS_005fIMAGE.html return_type=lambda node: UnresolvedType(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) TINY = IAttr( name="TINY", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=(Reference, Literal), arg_names=(("x",),) ), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "x"), reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["x"], ) ), ) TRAILZ = IAttr( name="TRAILZ", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("i",),)), optional_args={}, return_type=ScalarType.integer_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) TRANSFER = IAttr( name="TRANSFER", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("source", "mold"),)), optional_args={"size": DataNode}, return_type=lambda node: ( node.arguments[1].datatype.copy() if ("size" not in node.argument_names and not isinstance(node.argument_by_name("mold").datatype, ArrayType)) else ArrayType( ScalarType( node.argument_by_name("mold").datatype.intrinsic, node.argument_by_name("mold").datatype.precision ), [ArrayType.Extent.DEFERRED]) ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) TRANSPOSE = IAttr( name="TRANSPOSE", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("matrix",),)), optional_args={}, return_type=lambda node: ArrayType(ScalarType( node.argument_by_name("matrix").datatype.intrinsic, node.argument_by_name("matrix").datatype.precision), [node.argument_by_name("matrix").datatype.shape[1], node.argument_by_name("matrix").datatype.shape[0]] ), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) TRIM = IAttr( name="TRIM", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("string",),)), optional_args={}, return_type=ScalarType.character_type(), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) UBOUND = IAttr( name="UBOUND", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("array",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["array"], read_named_args=["dim"], constant_named_args=["kind"], ) ), ) UCOBOUND = IAttr( name="UCOBOUND", is_pure=True, is_elemental=False, is_inquiry=True, required_args=ArgDesc( min_count=1, max_count=1, types=DataNode, arg_names=(("coarray",),)), optional_args={"dim": DataNode, "kind": DataNode}, return_type=_get_bound_function_return_type, reference_accesses=lambda node: ( _compute_reference_accesses( node, inquiry_named_args=["array"], read_named_args=["dim"], constant_named_args=["kind"], ) ), ) UNPACK = IAttr( name="UNPACK", is_pure=True, is_elemental=False, is_inquiry=False, required_args=ArgDesc( min_count=3, max_count=3, types=DataNode, arg_names=(("vector", "mask", "field"),) ), optional_args={}, return_type=lambda node: _type_of_named_argument(node, "vector"), reference_accesses=lambda node: ( _compute_reference_accesses( node ) ), ) VERIFY = IAttr( name="VERIFY", is_pure=True, is_elemental=True, is_inquiry=False, required_args=ArgDesc( min_count=2, max_count=2, types=DataNode, arg_names=(("string", "set"),)), optional_args={"back": DataNode, "kind": DataNode}, return_type=lambda node: _type_of_scalar_with_optional_kind( node, ScalarType.Intrinsic.INTEGER, "kind" ), reference_accesses=lambda node: ( _compute_reference_accesses( node, constant_named_args=["kind"] ) ), ) def __hash__(self): return hash(self.name)
def __init__(self, intrinsic, **kwargs): if not isinstance(intrinsic, Enum) or intrinsic not in self.Intrinsic: raise TypeError( f"IntrinsicCall 'intrinsic' argument should be an " f"instance of IntrinsicCall.Intrinsic, but found " 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, ) ) ) @property def intrinsic(self): """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 @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 self.intrinsic.return_type is None: return NoType() if isinstance(self.intrinsic.return_type, Callable): try: return self.intrinsic.return_type(self) except TypeError as err: # If we get an invalid argument to a ScalarType constructor it # means we attempted to pass either an UnresolvedType into the # datatype if ("ScalarType expected 'intrinsic' argument to be of type " in str(err) or "ScalarType expected 'precision' argument to be of " "type " in str(err)): return UnresolvedType() # This should never happen, propogate as an InternalError. outerr = err except AttributeError as err: # This is to handle when we call .intrinsic or # .precision on an UnresolvedType # If we get an attribute error, and its because of attempting # to lookup the precision or intrinsic, then it is likely # due to looking up the datatype elements of an Unresolved # or UnsupportedType - in those cases then we should # return an UnresolvedType and not error. if (("has no attribute 'precision'" or "has no attribute 'intrinsic'" in str(err)) and "NoneType" not in str(err)): return UnresolvedType() outerr = err # Fall through to the internalerror. # Can't use debug string due to this being a potentially # incomplete IntrinsicCall raise InternalError( f"Failed to compute the datatype of a " f"'{self.intrinsic.name}' intrinsic. This is likely due " f"to not fully initialising the intrinsic correctly." ) from outerr else: return self.intrinsic.return_type
[docs] 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. :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: if len(self.arguments) > 1: return False if not device_string: return self.intrinsic in DEFAULT_DEVICE_INTRINISCS if device_string == "nvfortran-all": return self.intrinsic in NVFORTRAN_ALL if device_string == "nvfortran-uniform": return self.intrinsic in NVFORTRAN_UNIFORM raise ValueError( f"Unsupported device_string value '{device_string}', the supported" " values are '' (default), 'nvfortran-all', 'nvfortran-uniform'" )
def _find_matching_interface(self) -> Tuple[str]: ''' Finds the matching required argument interface for this node to add argument names from. :raises NotImplementedError: if there is not exactly one argument interface that matches this IntrinsicCall. ''' if len(self.intrinsic.required_args.arg_names) > 1: # Pull out the list of optional argument names. optional_names = list(self.intrinsic.optional_args.keys()) # Create a list of all the possible interface's argument lists. potential_interfaces: List[Tuple[str]] = [ names for names in self.intrinsic.required_args.arg_names ] # Remove any of the interfaces that don't contain # a named non-optional argument from the list of potential # candidate interfaces. for name in self.argument_names: if not name: continue # Need to check lower case. lname = name.lower() # Optional argument names are skipped over as they don't # affect which interface is being used. if lname in optional_names: continue for arglist in potential_interfaces: if lname not in arglist: potential_interfaces.remove(arglist) # Remove any of the interfaces that have too many or # too few *total* arguments to be candidates. for choice in potential_interfaces[:]: min_args = len(choice) max_args = min_args + len(optional_names) if (len(self.arguments) < min_args or len(self.arguments) > max_args): potential_interfaces.remove(choice) # Remove any of the interfaces that have too many or # too few *required* arguments to be candidates. # At this point the total arguments must be valid for all # remaining choices, and all named arguments must also be # present. for choice in potential_interfaces[:]: required_args = len(choice) # Check if the number of unnamed arguments is greater # than the number of required arguments. If so then # this choice is still acceptable (because optional # arguments can also be positional). num_positional_arguments = len( [x for x in self.argument_names if x is None] ) if num_positional_arguments >= required_args: continue # Otherwise we need to check if all the # required arguments are present as named arguments. # This operation pulls all the argument names from the # potential interface that are not already matched to a # positional argument in this IntrinsicCall. These must # be matched to named arguments in this IntrinsicCall, else # this interface cannot be a candidate for argument names. remaining_required = choice[num_positional_arguments:] for name in remaining_required: lname = name.lower() if lname not in self.argument_names: potential_interfaces.remove(choice) break # If we didn't reduce the number of potential interfaces to a # single interface then we can't add argument names. if (len(potential_interfaces) > 1 or len(potential_interfaces) == 0): raise NotImplementedError( f"Cannot add argument names to '{self.intrinsic.name}' " f"IntrinsicCall as PSyclone can't determine which " f"argument set it should use. This can be resolved by " f"using named arguments in the Fortran source." ) return potential_interfaces[0] elif len(self.intrinsic.required_args.arg_names) == 1: # This intrinsic only has a single possible interface. return self.intrinsic.required_args.arg_names[0] else: # This intrinsic has no required arguments. return ()
[docs] def compute_argument_names(self): '''Computes the argument names that correspond to the arguments of this IntrinsicCall, and add those argument names. If the interface is ambiguous, this function will raise an error. A small number of intrinsics (e.g. ALLOCATE, MAX) never have ambiguity and no argument limits, in which case no argument names are added. :raises ValueError: If the number of arguments or argument names are not valid for this IntrinsicCall. :raises NotImplementedError: If there is argument ambiguity and computation of argument names is not possible. ''' # First step is to convert all the argument names in the # intrinsic call to lower case. This also avoids constant # need to convert argument names to lower case when doing # comparisons. argument_names = self.argument_names for i, name in enumerate(argument_names): if name: self._argument_names[i] = (self._argument_names[i][0], name.lower()) # Get the optional argument names optional_names = list(self.intrinsic.optional_args.keys()) # If PSyclone can't handle the required args due # to them being non-finite or context sensitive, then skip # checking argument names (This is if [0][0] is None or ''). if (not (len(self.intrinsic.required_args.arg_names) == 1 and not self.intrinsic.required_args.arg_names[0][0])): # Get all valid argument names. all_valid_names = [ name for tupl in self.intrinsic.required_args.arg_names for name in tupl ] all_valid_names.extend(optional_names) # Check that all arguments names provided to this call are valid. # Raise ValueError if not. for name in self.argument_names: if not name: continue if name not in all_valid_names: raise ValueError( f"Found invalid argument name '{name}' when " f"computing argument names for the " f"'{self.intrinsic.name}' IntrinsicCall. Allowed " f"argument names are '{sorted(set(all_valid_names))}'." ) # Check that this call has a valid number of arguments if len(self.arguments) < self.intrinsic.required_args.min_count: raise ValueError( f"Found too few arguments when computing argument names for " f"the '{self.intrinsic.name}' IntrinsicCall. Requires at " f"least {self.intrinsic.required_args.min_count} " f"arguments but found {len(self.arguments)}." ) # If there is no maximum number of required arguments then we # can skip the rest of argument name computation, as this Intrinsic # can never have ambiguity. if self.intrinsic.required_args.max_count is None: return if (len(self.arguments) > (self.intrinsic.required_args.max_count + len(optional_names))): max_args = (self.intrinsic.required_args.max_count + len(optional_names)) raise ValueError( f"Found too many arguments when computing argument names " f"for the '{self.intrinsic.name}' IntrinsicCall. Requires at " f"most {max_args} arguments but found {len(self.arguments)}." ) # Find which intrinsic call interface we matching arguments to. interface_arg_names = self._find_matching_interface() # Handle cases where None or "" is in the interface_arg_names, # as this implies context sensitive argument naming which PSyclone # cannot handle. if interface_arg_names and not interface_arg_names[0]: # If we find any named non-optional named arguments for these # intrinsics then we can't add argument names to this # IntrinsicCall. # N.B. With currently supported intrinsics there are no # optional argument on these context-sensitive intrinsics # that have a finite argument count, but we keep the check # in case we need the support in future, and it still handles # what we currently need to check (i.e. if we have a named # argument here we can't add argument names to it safely). for name in self.argument_names: if not name: continue if name not in optional_names: raise NotImplementedError( f"Cannot add argument names to " f"'{self.intrinsic.name}' " f"as non-optional argument name '{name}' found " f"but the Intrinsic has context-sensitive argument " f"names which is unsupported by PSyclone." ) # The following rules are defined by the Fortran standard. # 1. Unnamed arguments must be in the order defined in the standard, # i.e. you cannot have LBOUND(1, 8, array=i). # 2. If all arguments are named, the order is entirely flexible, so # LBOUND(kind=8, dim=1, array=i) is allowed. # 3. All unnamed arguments will occur before any named arguments. # Name any unnamed arguments. for i, name in enumerate(self.argument_names): # If we find a named arg then we can exit this section. if name: break if i < len(interface_arg_names): # We found a required argument without a name. # Update the argument_names tuple with the corresponding # name from the matched interface. # If the argument name is '' then it needs to be None. if interface_arg_names[i]: self._argument_names[i] = (self._argument_names[i][0], interface_arg_names[i]) else: self._argument_names[i] = (self._argument_names[i][0], None) continue # Otherwise we found an optional argument, which will always # be in order if unnamed. self._argument_names[i] = (self._argument_names[i][0], optional_names[i - len( interface_arg_names)])
[docs] @classmethod def create(cls, intrinsic, arguments=()): '''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. :param intrinsic: the Intrinsic being called. :type intrinsic: py:class:`psyclone.psyir.IntrinsicCall.Intrinsic` :param arguments: list of arguments for this intrinsic, these can be PSyIR nodes or tuples of string,Node for named arguments. :type arguments: Optional[Iterable[\ Union[:py:class:`psyclone.psyir.nodes.DataNode`,\ Tuple[str, :py:class:`psyclone.psyir.nodes.DataNode`]]]] :returns: an instance of this class. :rtype: :py:class:`psyclone.psyir.nodes.IntrinsicCall` :raises TypeError: if any of the arguments are of the wrong type. :raises ValueError: if any optional arguments have incorrect names or if a positional argument is listed *after* a named argument. :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__}'") # Validate the supplied arguments. last_named_arg = None # Get all valid required argument names. valid_req_names = [ name for tupl in intrinsic.required_args.arg_names for name in tupl ] for arg in arguments: if isinstance(arg, tuple): if not isinstance(arg[0], str): 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.") name = arg[0].lower() last_named_arg = name if name in intrinsic.optional_args: if not isinstance(arg[1], intrinsic.optional_args[name]): raise TypeError( 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__}'") elif name in valid_req_names: if not isinstance(arg[1], intrinsic.required_args.types): raise TypeError( f"The argument '{name}' to intrinsic " f"'{intrinsic.name}' must be of type " f"'{intrinsic.required_args.types.__name__}' but " f"got '{type(arg[1]).__name__}'") else: if last_named_arg: raise ValueError( f"Found a positional argument *after* a named " 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__}'") # Create an intrinsic call and add the arguments # afterwards. We can't call the parent create method as it # assumes the intrinsic argument is a symbol and therefore tries # to create an intrinsic call with this symbol, rather than # the intrinsic enum. call._add_args(call, arguments) # Error check and add argument names to the call try: call.compute_argument_names() except (ValueError, NotImplementedError): # Since we fail adding argument names, we need to undo any links # created between nodes and return all inputs to their original # state before raising the error to the caller. for child in call.children: child.detach() # Rereaise the error. raise return call
[docs] def get_all_accessed_symbols(self) -> set[Symbol]: ''' :returns: a set of all the symbols accessed inside this IntrinsicCall. ''' symbols = set() for child in self.arguments: symbols.update(child.get_all_accessed_symbols()) return symbols
[docs] 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 accessors) and the values are AccessSequence (a sequence of AccessTypes). """ # Make sure argument names are computed if they currently haven't been if None in self.argument_names: try: self.compute_argument_names() except NotImplementedError: # If we can't compute argument names, then we have to # do the worst case (READWRITE). return _compute_reference_accesses( self, default_access=AccessType.READWRITE ) 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. @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.CEILING, ) # MATMUL can fail at link time depending on the precision of # its arguments. # IntrinsicCall.Intrinsic.MATMUL, # All nvfortran intrinsics available on GPUs NVFORTRAN_ALL = NVFORTRAN_UNIFORM + ( IntrinsicCall.Intrinsic.LOG10, IntrinsicCall.Intrinsic.REAL, ) # For now the default intrinsics available on GPU are the same as nvfortran-all DEFAULT_DEVICE_INTRINISCS = NVFORTRAN_ALL # TODO #658 this can be removed once we have support for determining the # type of a PSyIR expression. # Intrinsics that perform operations on an array. REDUCTION_INTRINSICS = [ IntrinsicCall.Intrinsic.SUM, IntrinsicCall.Intrinsic.MINVAL, IntrinsicCall.Intrinsic.MAXVAL, IntrinsicCall.Intrinsic.PACK, IntrinsicCall.Intrinsic.COUNT ]