예제 #1
0
def test_name():
    '''Check that the name property of the NemoAllArrayRange2LoopTrans
    class returns the expected value.

    '''
    assert (
        NemoAllArrayRange2LoopTrans().name == "NemoAllArrayRange2LoopTrans")
예제 #2
0
def test_apply_multi_assignments():
    '''Check that the apply() method can be called for multiple assigments
    with and without ranges.

    '''
    _, invoke_info = get_invoke("array_syntax.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    trans = NemoAllArrayRange2LoopTrans()
    for assignment in schedule.walk(Assignment):
        trans.apply(assignment)
    writer = FortranWriter()
    result = writer(schedule)
    expected = ("do jk = 1, jpk, 1\n"
                "  do jj = 1, jpj, 1\n"
                "    do ji = 1, jpi, 1\n"
                "      zftv(ji,jj,jk) = 0.0e0\n"
                "    enddo\n"
                "  enddo\n"
                "enddo\n"
                "if (l_ptr) then\n"
                "  call dia_ptr_hst(jn, ''ldf'', -zftv(:,:,:))\n"
                "end if\n"
                "call dia_ptr_hst(jn, ''ldf'', -zftv(:,:,:))\n"
                "do jj = 1, jpj, 1\n"
                "  do ji = 1, jpi, 1\n"
                "    zftu(ji,jj,1) = 1.0e0\n"
                "  enddo\n"
                "enddo\n"
                "do jj = 1, jpj, 1\n"
                "  do ji = 1, jpi, 1\n"
                "    tmask(ji,jj) = jpi\n"
                "  enddo\n"
                "enddo\n")
    assert expected in result
예제 #3
0
def test_str():
    '''Test that the str of an instance of the NemoAllArrayRange2LoopTrans
    class returns the expected value.

    '''
    assert (str(NemoAllArrayRange2LoopTrans()) == "Convert all array ranges "
            "in a PSyIR assignment into PSyIR NemoLoops.")
예제 #4
0
def test_apply_calls_validate():
    '''Check that the apply() method calls the validate method.'''
    trans = NemoAllArrayRange2LoopTrans()
    with pytest.raises(TransformationError) as info:
        trans.apply(None)
    assert ("Error in NemoAllArrayRange2LoopTrans transformation. The "
            "supplied node argument should be a PSyIR Assignment, but "
            "found 'NoneType'." in str(info.value))
예제 #5
0
def trans(psy):
    '''Transformation routine for use with PSyclone. Applies the PSyIR2SIR
    transform to the supplied invokes after replacing any ABS, SIGN or
    MIN intrinsics with equivalent code. This is done because the SIR
    does not support intrinsics.

    :param psy: the PSy object which this script will transform.
    :type psy: :py:class:`psyclone.psyGen.PSy`
    :returns: the transformed PSy object.
    :rtype: :py:class:`psyclone.psyGen.PSy`

    '''
    abs_trans = Abs2CodeTrans()
    sign_trans = Sign2CodeTrans()
    min_trans = Min2CodeTrans()
    nemo_loop_trans = NemoAllArrayRange2LoopTrans()

    sir_writer = SIRWriter()
    fortran_writer = FortranWriter()

    # For each Invoke write out the SIR representation of the
    # schedule. Note, there is no algorithm layer in the NEMO API so
    # the invokes represent all of the original code.
    for invoke in psy.invokes.invoke_list:
        schedule = invoke.schedule
        for assignment in schedule.walk(Assignment):
            nemo_loop_trans.apply(assignment)

        for kernel in schedule.walk(NemoKern):

            # The NEMO api currently has no symbol table so create one
            # to allow the generation of new variables. Note, this
            # does not guarantee unique names as we don't know any of
            # the existing names (so generated names could clash).
            symbol_table = SymbolTable()

            kernel_schedule = kernel.get_kernel_schedule()
            for oper in kernel_schedule.walk(Operation):
                if oper.operator == UnaryOperation.Operator.ABS:
                    # Apply ABS transformation
                    abs_trans.apply(oper, symbol_table)
                elif oper.operator == BinaryOperation.Operator.SIGN:
                    # Apply SIGN transformation
                    sign_trans.apply(oper, symbol_table)
                elif oper.operator in [
                        BinaryOperation.Operator.MIN,
                        NaryOperation.Operator.MIN
                ]:
                    # Apply (2-n arg) MIN transformation
                    min_trans.apply(oper, symbol_table)
        kern = fortran_writer(schedule)
        print(kern)
        kern = sir_writer(schedule)
        print(kern)

    return psy
예제 #6
0
def test_validate_assignment():
    '''Check that the validate method raises an exception if the supplied
    argument is not an Assignment node.

    '''
    trans = NemoAllArrayRange2LoopTrans()
    with pytest.raises(TransformationError) as info:
        trans.validate(None)
    assert ("Error in NemoAllArrayRange2LoopTrans transformation. The "
            "supplied node argument should be a PSyIR Assignment, but "
            "found 'NoneType'." in str(info.value))
예제 #7
0
def test_transform_apply_mixed_implicit_do():
    '''Check that the PSyIR is transformed as expected for a lat,lon,levs
    loop with some of its indices accessed using array notation and
    some using explicit loops.  The resultant Fortran code is used to
    confirm the transformation has worked correctly.

    '''
    _, invoke_info = get_invoke("explicit_over_implicit.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    assignment = schedule[0].loop_body[0]
    trans = NemoAllArrayRange2LoopTrans()
    trans.apply(assignment)
    writer = FortranWriter()
    result = writer(schedule)
    expected = ("do jk = 1, jpk, 1\n"
                "  do jj = 1, jpj, 1\n"
                "    do ji = 1, jpi, 1\n"
                "      umask(ji,jj,jk) = vmask(ji,jj,jk) + 1.0\n"
                "    enddo\n"
                "  enddo\n"
                "enddo")
    assert expected in result
예제 #8
0
'''

from __future__ import print_function
from psyclone.domain.nemo.transformations import NemoAllArrayRange2LoopTrans
from psyclone.errors import InternalError
from psyclone.psyir.nodes import Assignment, CodeBlock, Call, Literal, Loop, \
    ACCLoopDirective
from psyclone.transformations import ACCLoopTrans, TransformationError, \
    ACCKernelsTrans

COLLAPSE_LOOPS = False
EXPAND_IMPLICIT_LOOPS = False

# Get the PSyclone transformations we will use
ARRAY_RANGE_TRANS = NemoAllArrayRange2LoopTrans()


def trans(psy):
    '''A PSyclone-script compliant transformation function. Applies
    OpenACC 'kernels' and 'data' directives to NEMO code.

    :param psy: The PSy layer object to apply transformations to.
    :type psy: :py:class:`psyclone.psyGen.PSy`
    '''

    print("Invokes found:\n{0}\n".format("\n".join(
        [str(name) for name in psy.invokes.names])))

    for invoke in psy.invokes.invoke_list:
예제 #9
0
def test_transform():
    '''Check that it is possible to create an instance of
    NemoArrayRange2LoopTrans and that it is a Transformation.

    '''
    assert isinstance(NemoAllArrayRange2LoopTrans(), Transformation)
예제 #10
0
def make_sir_compliant(schedule):
    '''
    Applies various transformations to the supplied schedule to replace any
    features that cannot be represented in SIR with alternative forms:

    1. Converts any accesses of individual array elements into 1-trip loops.
    2. Transforms array assignments into loops.
    3. Replaces any ABS, SIGN, MIN or MAX intrinsics with equivalent PSyIR.
    4. Hoists any loop-invariant assignments out of loops over levels.

    :param schedule: the schedule to transform.
    :type schedule: :py:class:`psyclone.psyir.nodes.Schedule`

    '''
    abs_trans = Abs2CodeTrans()
    sign_trans = Sign2CodeTrans()
    min_trans = Min2CodeTrans()
    max_trans = Max2CodeTrans()
    array_range_trans = NemoAllArrayRange2LoopTrans()
    array_access_trans = NemoAllArrayAccess2LoopTrans()
    hoist_trans = HoistTrans()

    # Transform any single index accesses in array assignments
    # (e.g. a(1)) into 1-trip loops.
    for assignment in schedule.walk(Assignment):
        array_access_trans.apply(assignment)

    # Transform any array assignments (Fortran ':' notation) into loops.
    for assignment in schedule.walk(Assignment):
        array_range_trans.apply(assignment)

    for kernel in schedule.walk(NemoKern):

        kernel_schedule = kernel.get_kernel_schedule()
        for oper in kernel_schedule.walk(Operation):
            if oper.operator == UnaryOperation.Operator.ABS:
                # Apply ABS transformation
                abs_trans.apply(oper)
            elif oper.operator == BinaryOperation.Operator.SIGN:
                # Apply SIGN transformation
                sign_trans.apply(oper)
            elif oper.operator in [BinaryOperation.Operator.MIN,
                                   NaryOperation.Operator.MIN]:
                # Apply (2-n arg) MIN transformation
                min_trans.apply(oper)
            elif oper.operator in [BinaryOperation.Operator.MAX,
                                   NaryOperation.Operator.MAX]:
                # Apply (2-n arg) MAX transformation
                max_trans.apply(oper)

    # Remove any loop invariant assignments inside k-loops to make
    # them perfectly nested. At the moment this transformation
    # does not perform any dependence analysis validation so could
    # move code that should not be moved, see issue
    # #1387. However, it is known that it is safe do apply this
    # transformation to this particular code
    # (tra_adv_compute.F90).
    for loop in schedule.loops():
        # outermost only
        if loop.loop_type == "levels":
            for child in loop.loop_body[:]:
                if isinstance(child, Assignment):
                    hoist_trans.apply(child)