Exemple #1
0
def test_transform():
    '''Check that it is possible to create an instance of
    NemoArrayRange2LoopTrans and that it is a Transformation.

    '''
    assert NemoArrayRange2LoopTrans()
    assert isinstance(NemoArrayRange2LoopTrans(), Transformation)
Exemple #2
0
def test_apply_reference_literal():
    '''Check that the apply method add bounds appropriately when the
    config file specifies a lower bound as a reference and an upper
    bound as a literal.

    '''
    _, invoke_info = get_invoke("implicit_many_dims.f90", api=API, idx=0)
    # Create a new config instance and load a test config file with
    # the bounds information set the way we want.
    config = Config.get(do_not_load_file=True)
    config.load(config_file=TEST_CONFIG)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    for index in range(4, -1, -1):
        range_node = array_ref.children[index]
        trans.apply(range_node)
    # Remove this config file so the next time the default one will be
    # loaded (in case we affect other tests)
    Config._instance = None
    writer = FortranWriter()
    result = writer(schedule)
    assert ("do idx = LBOUND(umask, 5), UBOUND(umask, 5), 1\n"
            "  do jt = 1, UBOUND(umask, 4), 1\n"
            "    do jk = jpk, 1, 1\n"
            "      do jj = 1, jpj, 1\n"
            "        do ji = jpi, 1, 1\n"
            "          umask(ji,jj,jk,jt,idx) = vmask(ji,jj,jk,jt,idx) + 1.0\n"
            "        enddo\n"
            "      enddo\n"
            "    enddo\n"
            "  enddo\n"
            "enddo" in result)
Exemple #3
0
def test_str():
    '''Test that the str of an instance of the NemoArrayRange2LoopTrans class
    returns the expected value.

    '''
    assert (str(NemoArrayRange2LoopTrans()) == "Convert the PSyIR assignment "
            "for a specified ArrayReference Range into a PSyIR NemoLoop.")
Exemple #4
0
def test_apply_existing_names():
    '''Check that the apply method uses existing iterators appropriately
    when their symbols are already defined.

    '''
    _, invoke_info = get_invoke("implicit_do.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    symbol_table = schedule.symbol_table
    symbol_table.add(DataSymbol("ji", INTEGER_TYPE))
    symbol_table.add(DataSymbol("jj", INTEGER_TYPE))
    symbol_table.add(DataSymbol("jk", INTEGER_TYPE))

    trans.apply(array_ref.children[2])
    trans.apply(array_ref.children[1])
    trans.apply(array_ref.children[0])

    writer = FortranWriter()
    result = writer(schedule)
    assert ("do jk = 1, jpk, 1\n"
            "  do jj = 1, jpj, 1\n"
            "    do ji = 1, jpi, 1\n"
            "      umask(ji,jj,jk) = 0.0e0\n"
            "    enddo\n"
            "  enddo\n"
            "enddo" in result)
Exemple #5
0
def test_apply_calls_validate():
    '''Check that the apply() method calls the validate method.'''
    trans = NemoArrayRange2LoopTrans()
    with pytest.raises(TransformationError) as info:
        trans.apply(None)
    assert ("Error in NemoArrayRange2LoopTrans transformation. The supplied "
            "node argument should be a PSyIR Range, but found 'NoneType'."
            in str(info.value))
Exemple #6
0
def test_valid_node():
    '''Check that the validate() method raises the expected exception if
    the supplied node is invalid.

    '''
    trans = NemoArrayRange2LoopTrans()
    with pytest.raises(TransformationError) as info:
        trans.validate(None)
    assert ("Error in NemoArrayRange2LoopTrans transformation. The supplied "
            "node argument should be a PSyIR Range, but found 'NoneType'."
            in str(info.value))
Exemple #7
0
def test_apply_different_num_dims():
    '''Check that the apply method raises an exception when the number of
    range dimensions differ in different arrays. This should never
    happen as it is invalid PSyIR.

    '''
    _, invoke_info = get_invoke("implicit_mismatch_error.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    with pytest.raises(InternalError) as info:
        trans.apply(array_ref.children[1])
    assert ("The number of ranges in the arrays within this "
            "assignment are not equal. This is invalid PSyIR and "
            "should never happen." in str(info.value))
Exemple #8
0
def test_not_outermost_range():
    '''Check that the validate() method raises the expected exception if
    the supplied node is not the outermost Range within an array
    reference.

    '''
    _, invoke_info = get_invoke("implicit_do2.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    my_range = array_ref.children[0]
    with pytest.raises(TransformationError) as info:
        trans.validate(my_range)
    assert ("Error in NemoArrayRange2LoopTrans transformation. This "
            "transformation can only be applied to the outermost "
            "Range." in str(info.value))
Exemple #9
0
def test_array_valued_operator():
    '''Check that the vaidate() method raises the expected exception if an
    array valued operation is found on the rhs of the assignment node.

    '''
    _, invoke_info = get_invoke("array_valued_operation.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    with pytest.raises(TransformationError) as info:
        trans.apply(array_ref.children[0])
    assert (
        "Error in NemoArrayRange2LoopTrans transformation. This "
        "transformation does not support array valued operations on the rhs "
        "of the associated Assignment node, but found 'MATMUL'."
        in str(info.value))
Exemple #10
0
def test_within_lhs_assignment():
    '''Check that the validate() method raises the expected exception if
    the supplied node is not within an array reference that is within
    the lhs of an assignment (i.e. it is within the rhs).

    '''
    _, invoke_info = get_invoke("implicit_do2.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.rhs
    trans = NemoArrayRange2LoopTrans()
    my_range = array_ref.children[0]
    with pytest.raises(TransformationError) as info:
        trans.validate(my_range)
    assert ("Error in NemoArrayRange2LoopTrans transformation. The "
            "supplied node argument should be within an ArrayReference "
            "node that is within the left-hand-side of an Assignment "
            "node, but it is on the right-hand-side." in str(info.value))
Exemple #11
0
def test_apply_array_valued_function():
    '''Check that the apply method does not modify range nodes when they are
    used to specify the part of an array to pass into an array valued
    function.

    '''
    _, invoke_info = get_invoke("array_valued_function.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[1]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    trans.apply(array_ref.children[2])
    writer = FortranWriter()
    result = writer(schedule)
    assert ("jn = 2\n"
            "do jk = 1, jpk, 1\n"
            "  z3d(1,:,jk) = ptr_sjk(pvtr(:,:,:),btmsk(:,:,jn) * btm30(:,:))\n"
            "enddo" in result)
Exemple #12
0
def test_loop_variable_name_error(datatype):
    '''Check that the expected exception is raised when the config file
    specifies a loop iteration name but it is already declared in the
    code as something that is not a scalar.

    '''
    _, invoke_info = get_invoke("implicit_do.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    symbol_table = schedule.symbol_table
    symbol_table.add(DataSymbol("jk", datatype))
    with pytest.raises(TransformationError) as info:
        trans.apply(array_ref.children[2])
    assert ("The config file specifies 'jk' as the name of the iteration "
            "variable but this is already declared in the code as something "
            "that is not a scalar integer, or is a deferred type."
            in str(info.value))
Exemple #13
0
def test_within_array_reference():
    '''Check that the validate() method raises the expected exception if
    the supplied node is not within an array reference.

    '''
    _, invoke_info = get_invoke("implicit_do.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    my_range = array_ref.children[2]
    for parent, result in [(assignment, "Assignment"), (None, "NoneType")]:
        my_range._parent = parent
        with pytest.raises(TransformationError) as info:
            trans.validate(my_range)
        assert ("Error in NemoArrayRange2LoopTrans transformation. The "
                "supplied node argument should be within an "
                "ArrayReference node, but found '{0}'.".format(result)
                in str(info.value))
Exemple #14
0
def test_apply_var_name():
    '''Check that the variable name that is used when no names are
    specified in the config file does not clash with an existing symbol.

    '''
    _, invoke_info = get_invoke("implicit_many_dims.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    symbol_table = schedule.symbol_table
    symbol_table.add(DataSymbol("idx", INTEGER_TYPE))
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    range_node = array_ref.children[4]
    trans.apply(range_node)
    writer = FortranWriter()
    result = writer(schedule)
    assert ("do idx_1 = LBOUND(umask, 5), UBOUND(umask, 5), 1\n"
            "  umask(:,:,:,:,idx_1) = vmask(:,:,:,:,idx_1) + 1.0\n"
            "enddo" in result)
    def apply(self, node, options=None):
        '''Apply the NemoOuterArrayRange2Loop transformation to the specified
        node if the node is an Assignment and the left-hand-side of
        the assignment is an Array Reference containing at least one
        Range node specifying an access to an array index. If this is
        the case then the outermost Range nodes within array
        references within the assignment are replaced with references
        to a loop index. A NemoLoop loop (with the same loop index) is
        also placed around the modified assignment statement. If the
        array reference on the left-hand-side of the assignment only
        had one range node as an index (so now has none) then the
        assigment is also placed within a NemoKern.

        The name of the loop index is taken from the PSyclone
        configuration file if a name exists for the particular array
        index, otherwise a new name is generated. The bounds of the
        loop are taken from the Range node if they are provided. If
        not, the loop bounds are taken from the PSyclone configuration
        file if bounds values are supplied. If not, the LBOUND or
        UBOUND intrinsics are used as appropriate. The type of the
        NemoLoop is also taken from the configuration file if it is
        supplied for that index, otherwise it is specified as being
        "unknown".

        :param node: an Assignment node.
        :type node: :py:class:`psyclone.psyir.nodes.Assignment`
        :param options: a dictionary with options for \
            transformations. No options are used in this \
            transformation. This is an optional argument that defaults \
            to None.
        :type options: dict of string:values or None

        '''
        self.validate(node)

        # get lhs array
        lhs_array_ref = node.lhs
        index = get_outer_index(lhs_array_ref)
        nemo_arrayrange2loop = NemoArrayRange2LoopTrans()
        nemo_arrayrange2loop.apply(lhs_array_ref.children[index])
Exemple #16
0
def test_apply_fixed_bounds():
    '''Check that the apply method uses bounds information from the range
    node if it is supplied.

    '''
    _, invoke_info = get_invoke("implicit_do_slice.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    for index in range(2, -1, -1):
        range_node = array_ref.children[index]
        trans.apply(range_node)
    writer = FortranWriter()
    result = writer(schedule)
    assert ("do jk = 1, jpk, 1\n"
            "  do jj = 2, 4, 1\n"
            "    do ji = 1, jpi, 1\n"
            "      umask(ji,jj,jk) = 0.0e0\n"
            "    enddo\n"
            "  enddo\n"
            "enddo" in result)
Exemple #17
0
def test_apply_different_dims():
    '''Check that the apply method adds loop iterators appropriately when
    the range dimensions differ in different arrays.

    '''
    _, invoke_info = get_invoke("implicit_different_dims.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    for index in [4, 2, 0]:
        range_node = array_ref.children[index]
        trans.apply(range_node)
    writer = FortranWriter()
    result = writer(schedule)
    assert (
        "do idx = LBOUND(umask, 5), UBOUND(umask, 5), 1\n"
        "  do jk = 1, jpk, 1\n"
        "    do ji = 1, jpi, 1\n"
        "      umask(ji,jpj,jk,ndim,idx) = vmask(jpi,ji,jk,idx,ndim) + 1.0\n"
        "    enddo\n"
        "  enddo\n"
        "enddo" in result)
def test_apply_bounds():
    '''Check that the apply method uses a) configuration bounds if they
    are provided or b) lbound and ubound intrinsics when no bounds
    information is available. Also check that a NemoKern is added
    between the assignment and the innermost enclosing loop after the
    last range has been transformed into an explicit loop.

    '''
    _, invoke_info = get_invoke("implicit_many_dims.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0]
    array_ref = assignment.lhs
    trans = NemoArrayRange2LoopTrans()
    for index in range(4, -1, -1):
        assert not schedule.walk(NemoKern)
        range_node = array_ref.children[index]
        trans.apply(range_node)
    assert schedule.walk(NemoKern)
    assert isinstance(assignment.parent, Schedule)
    assert isinstance(assignment.parent.parent, NemoKern)
    assert isinstance(assignment.parent.parent.parent, Schedule)
    assert isinstance(assignment.parent.parent.parent.parent, NemoLoop)
    assert assignment.parent.parent.parent.parent.loop_type == "lon"
    writer = FortranWriter()
    result = writer(schedule)
    assert (
        "do idx = LBOUND(umask, 5), UBOUND(umask, 5), 1\n"
        "  do jt = 1, UBOUND(umask, 4), 1\n"
        "    do jk = 1, jpk, 1\n"
        "      do jj = 1, jpj, 1\n"
        "        do ji = 1, jpi, 1\n"
        "          umask(ji,jj,jk,jt,idx) = vmask(ji,jj,jk,jt,idx) + 1.0\n"
        "        enddo\n"
        "      enddo\n"
        "    enddo\n"
        "  enddo\n"
        "enddo" in result)
Exemple #19
0
def test_name():
    '''Check that the name property of the ArrayRange2LoopTrans class
    returns the expected value.

    '''
    assert NemoArrayRange2LoopTrans().name == "NemoArrayRange2LoopTrans"