Ejemplo n.º 1
0
def test_compiler_works(tmpdir):
    ''' Check that the specified compiler works for a hello-world
    example '''
    Compile.skip_if_compilation_disabled()

    old_pwd = tmpdir.chdir()
    try:
        with open("hello_world.f90", "w") as ffile:
            ffile.write(HELLO_CODE)
        Compile(tmpdir).compile_file("hello_world.f90", link=True)
    finally:
        old_pwd.chdir()
Ejemplo n.º 2
0
def test_find_fortran_file(tmpdir):
    ''' Check that our find_fortran_file routine raises the expected
    error if it can't find a matching file. Also check that it returns
    the correct name if the file does exist. '''
    with pytest.raises(IOError) as excinfo:
        Compile.find_fortran_file([str(tmpdir)], "missing_file")
    assert "missing_file' with suffix in ['f90', 'F90'," in str(excinfo)
    old_pwd = tmpdir.chdir()
    try:
        with open("hello_world.f90", "w") as ffile:
            ffile.write(HELLO_CODE)
        name = Compile.find_fortran_file([str(tmpdir)], "hello_world")
        assert name.endswith("hello_world.f90")
    finally:
        old_pwd.chdir()
Ejemplo n.º 3
0
def test_correct(func, output, tmpdir):
    '''Check that a valid example produces the expected output when the
    argument to ABS is a simple argument and when it is an
    expresssion.

    '''
    Config.get().api = "nemo"
    operation = example_psyir(func)
    writer = FortranWriter()
    result = writer(operation.root)
    assert ("subroutine abs_example(arg)\n"
            "  real, intent(inout) :: arg\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp = ABS({0})\n\n"
            "end subroutine abs_example\n".format(output)) in result
    trans = Abs2CodeTrans()
    trans.apply(operation, operation.root.symbol_table)
    result = writer(operation.root)
    assert ("subroutine abs_example(arg)\n"
            "  real, intent(inout) :: arg\n"
            "  real :: psyir_tmp\n"
            "  real :: res_abs\n"
            "  real :: tmp_abs\n\n"
            "  tmp_abs = {0}\n"
            "  if (tmp_abs > 0.0) then\n"
            "    res_abs = tmp_abs\n"
            "  else\n"
            "    res_abs = tmp_abs * -1.0\n"
            "  end if\n"
            "  psyir_tmp = res_abs\n\n"
            "end subroutine abs_example\n".format(output)) in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 4
0
def test_apply2(tmpdir):
    '''Test that the matmul2code apply method produces the expected
    PSyIR. We use the Fortran backend to help provide the test for
    correctness. This example includes extra indices for the vector
    and matrix arrays with additional indices being literals.

    '''
    trans = Matmul2CodeTrans()
    matmul = create_matmul()
    matmul.children[0].children[2] = Literal("1", INTEGER_TYPE)
    matmul.children[1].children[1] = Literal("2", INTEGER_TYPE)
    trans.apply(matmul)
    writer = FortranWriter()
    result = writer(matmul.root)
    assert ("subroutine my_kern()\n"
            "  integer, parameter :: idx = 3\n"
            "  real, dimension(5,10,15) :: x\n"
            "  real, dimension(10,20) :: y\n"
            "  real, dimension(10) :: result\n"
            "  integer :: i\n"
            "  integer :: j\n"
            "\n"
            "  do i = 1, 5, 1\n"
            "    result(i)=0.0\n"
            "    do j = 1, 10, 1\n"
            "      result(i)=result(i) + x(i,j,1) * y(j,2)\n"
            "    enddo\n"
            "  enddo\n"
            "\n"
            "end subroutine my_kern" in result)
    assert Compile(tmpdir).string_compiles(result)
Ejemplo n.º 5
0
def test_replicated_loop(parser, tmpdir):
    '''Check code generation with two loops that have the same
    structure.

    '''
    reader = FortranStringReader("subroutine replicate()\n"
                                 "   INTEGER :: dummy\n"
                                 "   REAL :: zwx(10,10)\n"
                                 "   zwx(:,:) = 0.e0\n"
                                 "   zwx(:,:) = 0.e0\n"
                                 "END subroutine replicate\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.get('replicate').schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    schedule, _ = acc_trans.apply(schedule.children[0:1])
    schedule, _ = acc_trans.apply(schedule.children[1:2])
    gen_code = str(psy.gen)

    assert ("  !$ACC DATA COPYOUT(zwx)\n"
            "  zwx(:, :) = 0.E0\n"
            "  !$ACC END DATA\n"
            "  !$ACC DATA COPYOUT(zwx)\n"
            "  zwx(:, :) = 0.E0\n"
            "  !$ACC END DATA" in gen_code)
    assert Compile(tmpdir).string_compiles(gen_code)
Ejemplo n.º 6
0
def test_correct_binary(func, output, tmpdir):
    '''Check that a valid example produces the expected output when the
    first argument to MIN is a simple argument and when it is an
    expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir_binary(func)
    writer = FortranWriter()
    result = writer(operation.root)
    assert ("subroutine min_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp=MIN({0}, arg_1)\n\n"
            "end subroutine min_example\n".format(output)) in result
    trans = Min2CodeTrans()
    trans.apply(operation, operation.root.symbol_table)
    result = writer(operation.root)
    assert ("subroutine min_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_min\n"
            "  real :: tmp_min\n\n"
            "  res_min={0}\n"
            "  tmp_min=arg_1\n"
            "  if (tmp_min < res_min) then\n"
            "    res_min=tmp_min\n"
            "  end if\n"
            "  psyir_tmp=res_min\n\n"
            "end subroutine min_example\n".format(output)) in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 7
0
def test_transform_apply_insert(tmpdir):
    '''Check that the PSyIR is transformed as expected when there are
    multiple statements in the PSyIR. The resultant Fortran code is used to
    confirm the transformation has worked correctly.

    '''
    trans = ArrayRange2LoopTrans()

    symbol_table = SymbolTable()
    symbol = DataSymbol("n", INTEGER_TYPE)
    symbol_table.add(symbol)
    # Create the first assignment. In Fortran notation: x(:) = y(n,:)
    lhs = create_array_x(symbol_table)
    rhs = create_array_y(symbol_table)
    assignment1 = Assignment.create(lhs, rhs)
    # Create the second assignment. In Fortran notation: y2(:,:) = z(:,n,:)
    lhs = create_array_y_2d_slice(symbol_table)
    rhs = create_array_z(symbol_table)
    assignment2 = Assignment.create(lhs, rhs)
    routine = KernelSchedule.create("work", symbol_table,
                                    [assignment1, assignment2])
    trans.apply(assignment1)
    trans.apply(assignment2)
    writer = FortranWriter()
    expected = ("  do idx = LBOUND(x, 1), UBOUND(x, 1), 1\n"
                "    x(idx)=y(n,idx)\n"
                "  enddo\n"
                "  do idx_1 = LBOUND(y2, 2), UBOUND(y2, 2), 1\n"
                "    y2(:,idx_1)=z(:,n,idx_1)\n"
                "  enddo\n")
    result = writer(routine)
    assert expected in result
    assert Compile(tmpdir).string_compiles(result)
Ejemplo n.º 8
0
def test_transform_multi_apply(tmpdir):
    '''Check that the ArrayRange2Loop transformation can be used to create
    nested loops by calling it multiple times when an array has
    multiple dimensions that use a range.

    '''
    trans = ArrayRange2LoopTrans()

    symbol_table = SymbolTable()
    symbol = DataSymbol("n", INTEGER_TYPE)
    symbol_table.add(symbol)
    lhs = create_array_y_2d_slice(symbol_table)
    rhs = create_array_z(symbol_table)
    assignment = Assignment.create(lhs, rhs)
    routine = KernelSchedule.create("work", symbol_table, [assignment])
    trans.apply(assignment)
    trans.apply(assignment)
    expected = ("  do idx = LBOUND(y2, 2), UBOUND(y2, 2), 1\n"
                "    do idx_1 = LBOUND(y2, 1), UBOUND(y2, 1), 1\n"
                "      y2(idx_1,idx)=z(idx_1,n,idx)\n"
                "    enddo\n"
                "  enddo\n")
    writer = FortranWriter()
    result = writer(routine)
    assert expected in result
    assert Compile(tmpdir).string_compiles(result)
Ejemplo n.º 9
0
def test_correct_2abs(tmpdir):
    '''Check that a valid example produces the expected output when there
    is more than one ABS() in an expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir(
        lambda arg: BinaryOperation.create(
            BinaryOperation.Operator.MUL, arg,
            Literal("3.14", REAL_TYPE)))
    root = operation.root
    assignment = operation.parent
    abs_op = UnaryOperation.create(UnaryOperation.Operator.ABS,
                                   Literal("1.0", REAL_TYPE))
    operation.detach()
    op1 = BinaryOperation.create(BinaryOperation.Operator.ADD,
                                 operation, abs_op)
    assignment.addchild(op1)
    writer = FortranWriter()
    result = writer(root)
    assert (
        "subroutine abs_example(arg)\n"
        "  real, intent(inout) :: arg\n"
        "  real :: psyir_tmp\n\n"
        "  psyir_tmp = ABS(arg * 3.14) + ABS(1.0)\n\n"
        "end subroutine abs_example\n") in result
    trans = Abs2CodeTrans()
    trans.apply(operation, root.symbol_table)
    trans.apply(abs_op, root.symbol_table)
    result = writer(root)
    assert (
        "subroutine abs_example(arg)\n"
        "  real, intent(inout) :: arg\n"
        "  real :: psyir_tmp\n"
        "  real :: res_abs\n"
        "  real :: tmp_abs\n"
        "  real :: res_abs_1\n"
        "  real :: tmp_abs_1\n\n"
        "  tmp_abs = arg * 3.14\n"
        "  if (tmp_abs > 0.0) then\n"
        "    res_abs = tmp_abs\n"
        "  else\n"
        "    res_abs = tmp_abs * -1.0\n"
        "  end if\n"
        "  tmp_abs_1 = 1.0\n"
        "  if (tmp_abs_1 > 0.0) then\n"
        "    res_abs_1 = tmp_abs_1\n"
        "  else\n"
        "    res_abs_1 = tmp_abs_1 * -1.0\n"
        "  end if\n"
        "  psyir_tmp = res_abs + res_abs_1\n\n"
        "end subroutine abs_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 10
0
def infra_compile(tmpdir_factory, request):
    '''A per-session initialisation function that sets the compilation flags
    in the Compile class based on command line options for --compile,
    --compileopencl, --f90, --f90flags. Then makes sure that the
    infrastructure files for the dynamo0p3 and gocean1p0 APIs are compiled
    (if compilation was enabled).
    '''
    Compile.store_compilation_flags(request.config)

    # Create a temporary directory to store the compiled files.
    # Note that this directory is unique even if compiled in
    # parallel, i.e. each process has its own copy of the
    # compiled infrastructure file, which avoids the problem
    # of synchronisation between the processes.
    tmpdir = tmpdir_factory.mktemp('dynamo_wrapper')
    # This is the first instance created. This will trigger
    # compilation of the infrastructure files.
    LFRicBuild(tmpdir)

    tmpdir = tmpdir_factory.mktemp('dl_esm_inf')
    GOcean1p0Build(tmpdir)
Ejemplo n.º 11
0
def test_correct_2min(tmpdir):
    '''Check that a valid example produces the expected output when there
    is more than one MIN() in an expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir_binary(lambda arg: arg)
    root = operation.root
    assignment = operation.parent
    operation.detach()
    min_op = BinaryOperation.create(BinaryOperation.Operator.MIN,
                                    Literal("1.0", REAL_TYPE),
                                    Literal("2.0", REAL_TYPE))
    op1 = BinaryOperation.create(BinaryOperation.Operator.ADD, min_op,
                                 operation)
    assignment.addchild(op1)

    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine min_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp = MIN(1.0, 2.0) + MIN(arg, arg_1)\n\n"
            "end subroutine min_example\n") in result
    trans = Min2CodeTrans()
    trans.apply(operation, root.symbol_table)
    trans.apply(min_op, root.symbol_table)
    result = writer(root)
    assert ("subroutine min_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_min\n"
            "  real :: tmp_min\n"
            "  real :: res_min_1\n"
            "  real :: tmp_min_1\n\n"
            "  res_min = arg\n"
            "  tmp_min = arg_1\n"
            "  if (tmp_min < res_min) then\n"
            "    res_min = tmp_min\n"
            "  end if\n"
            "  res_min_1 = 1.0\n"
            "  tmp_min_1 = 2.0\n"
            "  if (tmp_min_1 < res_min_1) then\n"
            "    res_min_1 = tmp_min_1\n"
            "  end if\n"
            "  psyir_tmp = res_min_1 + res_min\n\n"
            "end subroutine min_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 12
0
def test_compiler_with_flags(tmpdir):
    ''' Check that we can pass through flags to the Fortran compiler.
    Since correct flags are compiler-dependent and hard to test,
    we pass something that is definitely not a flag and check that
    the compiler complains. This test is skipped if no compilation
    tests have been requested (--compile flag to py.test). '''
    Compile.skip_if_compilation_disabled()
    old_pwd = tmpdir.chdir()
    try:
        with open("hello_world.f90", "w") as ffile:
            ffile.write(HELLO_CODE)
        _compile = Compile(tmpdir)
        _compile._f90flags = "not-a-flag"
        with pytest.raises(CompileError) as excinfo:
            _compile.compile_file("hello_world.f90")
        assert "not-a-flag" in str(excinfo.value)
        # For completeness we also try with a valid flag although we
        # can't actually check its effect.
        _compile._f90flags = "-g"
        _compile.compile_file("hello_world.f90", link=True)
    finally:
        old_pwd.chdir()
Ejemplo n.º 13
0
def test_opencl_compiler_works(kernel_outputdir):
    ''' Check that the specified compiler works for a hello-world
    opencl example. This is done in this file to alert the user
    that all compiles tests are skipped if only the '--compile'
    command line option is used (instead of --compileopencl)
    '''
    Compile.skip_if_opencl_compilation_disabled()
    example_ocl_code = '''
program hello
  USE fortcl
  write (*,*) "Hello"
end program hello
'''
    old_pwd = kernel_outputdir.chdir()
    try:
        with open("hello_world_opencl.f90", "w") as ffile:
            ffile.write(example_ocl_code)
        GOcean1p0OpenCLBuild(kernel_outputdir).\
            compile_file("hello_world_opencl.f90",
                         link=True)
    finally:
        old_pwd.chdir()
Ejemplo n.º 14
0
def test_correct_expr(tmpdir):
    '''Check that a valid example produces the expected output when SIGN
    is part of an expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir(lambda arg: BinaryOperation.create(
        BinaryOperation.Operator.MUL, arg, Literal("3.14", REAL_TYPE)))
    root = operation.root
    assignment = operation.parent
    operation.detach()
    op1 = BinaryOperation.create(BinaryOperation.Operator.ADD,
                                 Literal("1.0", REAL_TYPE), operation)
    op2 = BinaryOperation.create(BinaryOperation.Operator.ADD, op1,
                                 Literal("2.0", REAL_TYPE))
    assignment.addchild(op2)
    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine sign_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp = 1.0 + SIGN(arg * 3.14, arg_1) + 2.0\n\n"
            "end subroutine sign_example\n") in result
    trans = Sign2CodeTrans()
    trans.apply(operation, root.symbol_table)
    result = writer(root)
    assert ("subroutine sign_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_sign\n"
            "  real :: tmp_sign\n"
            "  real :: res_abs\n"
            "  real :: tmp_abs\n\n"
            "  tmp_abs = arg * 3.14\n"
            "  if (tmp_abs > 0.0) then\n"
            "    res_abs = tmp_abs\n"
            "  else\n"
            "    res_abs = tmp_abs * -1.0\n"
            "  end if\n"
            "  res_sign = res_abs\n"
            "  tmp_sign = arg_1\n"
            "  if (tmp_sign < 0.0) then\n"
            "    res_sign = res_sign * -1.0\n"
            "  end if\n"
            "  psyir_tmp = 1.0 + res_sign + 2.0\n\n"
            "end subroutine sign_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 15
0
def test_compile_str(monkeypatch, tmpdir):
    ''' Checks for the routine that compiles Fortran supplied as a string '''
    # Check that we always return True if compilation testing is disabled
    Compile.skip_if_compilation_disabled()
    _compile = Compile(tmpdir)
    test_compile = "psyclone.tests.utilities.Compile"
    monkeypatch.setattr(test_compile + ".TEST_COMPILE", False)
    monkeypatch.setattr(test_compile + ".TEST_COMPILE_OPENCL", False)
    assert _compile.string_compiles("not fortran")
    # Re-enable compilation testing and check that we can build hello world
    monkeypatch.setattr(test_compile + ".TEST_COMPILE", True)
    assert _compile.string_compiles(HELLO_CODE)
    # Repeat for some broken code
    invalid_code = HELLO_CODE.replace("write", "wite", 1)
    assert not _compile.string_compiles(invalid_code)
Ejemplo n.º 16
0
def test_apply3(tmpdir):
    '''Test that the matmul2code apply method produces the expected
    PSyIR. We use the Fortran backend to help provide the test for
    correctness. This example includes the array and vector being
    passed with no index information.

    '''
    trans = Matmul2CodeTrans()
    matmul = create_matmul()
    root = matmul.root
    matrix = matmul.children[0]
    lhs_vector = matrix.parent.parent.lhs
    matrix_symbol = matrix.symbol
    matmul.children[0] = Reference(matrix_symbol)
    matrix_symbol.datatype._shape = [
        Literal("10", INTEGER_TYPE),
        Literal("20", INTEGER_TYPE)
    ]
    rhs_vector = matmul.children[1]
    rhs_vector_symbol = rhs_vector.symbol
    rhs_vector_symbol.datatype._shape = [Literal("20", INTEGER_TYPE)]
    matmul.children[1] = Reference(rhs_vector_symbol)
    lhs_vector_symbol = lhs_vector.symbol
    lhs_vector_symbol._shape = [Literal("10", INTEGER_TYPE)]
    lhs_vector.replace_with(Reference(lhs_vector_symbol))
    trans.apply(matmul)
    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine my_kern()\n"
            "  integer, parameter :: idx = 3\n"
            "  real, dimension(10,20) :: x\n"
            "  real, dimension(20) :: y\n"
            "  real, dimension(10) :: result\n"
            "  integer :: i\n"
            "  integer :: j\n"
            "\n"
            "  do i = 1, 10, 1\n"
            "    result(i) = 0.0\n"
            "    do j = 1, 20, 1\n"
            "      result(i) = result(i) + x(i,j) * y(j)\n"
            "    enddo\n"
            "  enddo\n"
            "\n"
            "end subroutine my_kern" in result)
    assert Compile(tmpdir).string_compiles(result)
Ejemplo n.º 17
0
def test_transform_apply(lhs_create, rhs_create, expected, tmpdir):
    '''Check that the PSyIR is transformed as expected for various types
    of ranges in an array. The resultant Fortran code is used to
    confirm the transformation has worked correctly.

    '''
    trans = ArrayRange2LoopTrans()
    symbol_table = SymbolTable()
    symbol = DataSymbol("n", INTEGER_TYPE)
    symbol_table.add(symbol)
    lhs = lhs_create(symbol_table)
    rhs = rhs_create(symbol_table)
    assignment = Assignment.create(lhs, rhs)
    routine = KernelSchedule.create("work", symbol_table, [assignment])
    trans.apply(assignment)
    writer = FortranWriter()
    result = writer(routine)
    assert expected in result
    assert Compile(tmpdir).string_compiles(result)
Ejemplo n.º 18
0
def test_correct_expr(tmpdir):
    '''Check that a valid example produces the expected output when MIN()
    is part of an expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir_binary(lambda arg: arg)
    assignment = operation.parent
    op1 = BinaryOperation.create(BinaryOperation.Operator.ADD,
                                 Literal("1.0", REAL_TYPE), operation)
    op2 = BinaryOperation.create(BinaryOperation.Operator.ADD, op1,
                                 Literal("2.0", REAL_TYPE))
    op2.parent = assignment
    assignment.children[1] = op2

    writer = FortranWriter()
    result = writer(operation.root)
    assert ("subroutine min_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp=1.0 + MIN(arg, arg_1) + 2.0\n\n"
            "end subroutine min_example\n") in result
    trans = Min2CodeTrans()
    trans.apply(operation, operation.root.symbol_table)
    result = writer(operation.root)
    assert ("subroutine min_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_min\n"
            "  real :: tmp_min\n\n"
            "  res_min=arg\n"
            "  tmp_min=arg_1\n"
            "  if (tmp_min < res_min) then\n"
            "    res_min=tmp_min\n"
            "  end if\n"
            "  psyir_tmp=1.0 + res_min + 2.0\n\n"
            "end subroutine min_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 19
0
def test_correct_nary(tmpdir):
    '''Check that a valid example with an nary MIN produces the expected
    output.

    '''
    Config.get().api = "nemo"
    operation = example_psyir_nary()
    root = operation.root
    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine min_example(arg, arg_1, arg_2)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real, intent(inout) :: arg_2\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp = MIN(arg, arg_1, arg_2)\n\n"
            "end subroutine min_example\n") in result
    trans = Min2CodeTrans()
    trans.apply(operation, operation.root.symbol_table)
    result = writer(root)
    assert ("subroutine min_example(arg, arg_1, arg_2)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real, intent(inout) :: arg_2\n"
            "  real :: psyir_tmp\n"
            "  real :: res_min\n"
            "  real :: tmp_min\n\n"
            "  res_min = arg\n"
            "  tmp_min = arg_1\n"
            "  if (tmp_min < res_min) then\n"
            "    res_min = tmp_min\n"
            "  end if\n"
            "  tmp_min = arg_2\n"
            "  if (tmp_min < res_min) then\n"
            "    res_min = tmp_min\n"
            "  end if\n"
            "  psyir_tmp = res_min\n\n"
            "end subroutine min_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 20
0
def test_build_invalid_fortran(tmpdir):
    ''' Check that we raise the expected error when attempting
    to compile some invalid Fortran. Skips test if --compile not
    supplied to py.test on command-line. '''
    Compile.skip_if_compilation_disabled()
    invalid_code = HELLO_CODE.replace("write", "wite", 1)
    old_pwd = tmpdir.chdir()
    try:
        with open("hello_world.f90", "w") as ffile:
            ffile.write(invalid_code)
        _compile = Compile(tmpdir)
        with pytest.raises(CompileError) as excinfo:
            _compile.compile_file("hello_world.f90")
    finally:
        old_pwd.chdir()
    assert "Compile error" in str(excinfo.value)
Ejemplo n.º 21
0
def test_fuse_correct_bounds(tmpdir, fortran_reader, fortran_writer):
    '''
    Test that loop boundaries must be identical.
    '''
    # TODO: This test needs evaluation
    # of constant expressions in PSyclone
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=2, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=2, n+1-1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''
    out, _ = fuse_loops(code, fortran_reader, fortran_writer)
    assert Compile(tmpdir).string_compiles(out)
Ejemplo n.º 22
0
def test_apply4(tmpdir):
    '''Test that the matmul2code apply method produces the expected
    PSyIR. We use the Fortran backend to help provide the test for
    correctness. This example make the lhs be the same array as the
    second operand of the matmul (the vector in this case).

    '''
    trans = Matmul2CodeTrans()
    one = Literal("1", INTEGER_TYPE)
    five = Literal("5", INTEGER_TYPE)
    matmul = create_matmul()
    root = matmul.root
    assignment = matmul.parent
    vector = assignment.scope.symbol_table.lookup("y")
    assignment.children[0] = ArrayReference.create(
        vector, [Range.create(one, five, one.copy()),
                 one.copy()])
    trans.apply(matmul)
    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine my_kern()\n"
            "  integer, parameter :: idx = 3\n"
            "  real, dimension(5,10,15) :: x\n"
            "  real, dimension(10,20) :: y\n"
            "  real, dimension(10) :: result\n"
            "  integer :: i\n"
            "  integer :: j\n"
            "\n"
            "  do i = 1, 5, 1\n"
            "    y(i,1) = 0.0\n"
            "    do j = 1, 10, 1\n"
            "      y(i,1) = y(i,1) + x(i,j,idx) * y(j,idx)\n"
            "    enddo\n"
            "  enddo\n"
            "\n"
            "end subroutine my_kern" in result)
    assert Compile(tmpdir).string_compiles(result)
Ejemplo n.º 23
0
def test_correct_2sign(tmpdir):
    '''Check that a valid example produces the expected output when there
    is more than one SIGN in an expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir(lambda arg: BinaryOperation.create(
        BinaryOperation.Operator.MUL, arg, Literal("3.14", REAL_TYPE)))
    assignment = operation.parent
    sign_op = BinaryOperation.create(BinaryOperation.Operator.SIGN,
                                     Literal("1.0", REAL_TYPE),
                                     Literal("1.0", REAL_TYPE))
    op1 = BinaryOperation.create(BinaryOperation.Operator.ADD, sign_op,
                                 operation)
    op1.parent = assignment
    assignment.children[1] = op1
    writer = FortranWriter()
    result = writer(operation.root)
    assert ("subroutine sign_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp=SIGN(1.0, 1.0) + SIGN(arg * 3.14, arg_1)\n\n"
            "end subroutine sign_example\n") in result
    trans = Sign2CodeTrans()
    trans.apply(operation, operation.root.symbol_table)
    trans.apply(sign_op, operation.root.symbol_table)
    result = writer(operation.root)
    assert ("subroutine sign_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_sign\n"
            "  real :: tmp_sign\n"
            "  real :: res_abs\n"
            "  real :: tmp_abs\n"
            "  real :: res_sign_1\n"
            "  real :: tmp_sign_1\n"
            "  real :: res_abs_1\n"
            "  real :: tmp_abs_1\n\n"
            "  tmp_abs=arg * 3.14\n"
            "  if (tmp_abs > 0.0) then\n"
            "    res_abs=tmp_abs\n"
            "  else\n"
            "    res_abs=tmp_abs * -1.0\n"
            "  end if\n"
            "  res_sign=res_abs\n"
            "  tmp_sign=arg_1\n"
            "  if (tmp_sign < 0.0) then\n"
            "    res_sign=res_sign * -1.0\n"
            "  end if\n"
            "  tmp_abs_1=1.0\n"
            "  if (tmp_abs_1 > 0.0) then\n"
            "    res_abs_1=tmp_abs_1\n"
            "  else\n"
            "    res_abs_1=tmp_abs_1 * -1.0\n"
            "  end if\n"
            "  res_sign_1=res_abs_1\n"
            "  tmp_sign_1=1.0\n"
            "  if (tmp_sign_1 < 0.0) then\n"
            "    res_sign_1=res_sign_1 * -1.0\n"
            "  end if\n"
            "  psyir_tmp=res_sign_1 + res_sign\n\n"
            "end subroutine sign_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
Ejemplo n.º 24
0
def test_fuse_scalars(tmpdir, fortran_reader, fortran_writer):
    '''Test that using scalars work as expected in all combinations of
    being read/written in both loops.
    '''

    # First test: read/read of scalar variable
    code = '''subroutine sub()
              integer :: ji, jj, n
              real, dimension(10,10) :: s, t
              real                   :: a
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj) = t(ji, jj) + a
                 enddo
              enddo
              do jj=1, n
                 do ji=1, 10
                    t(ji, jj) = t(ji, jj) - a
                 enddo
              enddo
              end subroutine sub'''
    out, _ = fuse_loops(code, fortran_reader, fortran_writer)
    assert Compile(tmpdir).string_compiles(out)

    # Second test: read/write of scalar variable
    code = '''subroutine sub()
              integer :: ji, jj, n
              real, dimension(10,10) :: s, t
              real                   :: a
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+a
                 enddo
              enddo
              do jj=1, n
                 do ji=1, 10
                    a = t(ji, jj) - 2
                    s(ji, jj)=t(ji, jj)+a
                 enddo
              enddo
              end subroutine sub'''

    with pytest.raises(TransformationError) as err:
        fuse_loops(code, fortran_reader, fortran_writer)
    assert "Scalar variable 'a' is written in one loop, but only read in " \
           "the other loop." in str(err.value)

    # Third test: write/read of scalar variable
    code = '''subroutine sub()
              integer :: ji, jj, n
              real, dimension(10,10) :: s, t
              real                   :: b
              do jj=1, n
                 do ji=1, 10
                    b = t(ji, jj) - 2
                    s(ji, jj )=t(ji, jj)+b
                 enddo
              enddo
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+b
                 enddo
              enddo
              end subroutine sub'''

    with pytest.raises(TransformationError) as err:
        fuse_loops(code, fortran_reader, fortran_writer)
    assert "Scalar variable 'b' is written in one loop, but only read in " \
           "the other loop." in str(err.value)

    # Fourth test: write/write of scalar variable - this is ok
    code = '''subroutine sub()
              integer :: ji, jj, n
              real, dimension(10,10) :: s, t
              real                   :: b
              do jj=1, n
                 do ji=1, 10
                    b = t(ji, jj) - 2
                    s(ji, jj )=t(ji, jj)+b
                 enddo
              enddo
              do jj=1, n
                 do ji=1, 10
                    b = sqrt(t(ji, jj))
                    s(ji, jj)=t(ji, jj)+b
                 enddo
              enddo
              end subroutine sub'''
    out, _ = fuse_loops(code, fortran_reader, fortran_writer)
    assert Compile(tmpdir).string_compiles(out)
Ejemplo n.º 25
0
def test_fuse_dimension_change(tmpdir, fortran_reader, fortran_writer):
    '''Test that inconsistent use of dimemsions are detected, e.g.:
    loop1:  a(i,j)
    loop2:  a(j,i)
    when at least one operation is a write
    '''

    # The first example can be merged, since 't' is read-only,
    # so it doesn't matter that it is accessed differently
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=1, n+1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=1, n+1
                 do ji=1, 10
                    s(ji, jj)=s(ji, jj) + t(jj, jj) + t(ji, ji)
                 enddo
              enddo
              end subroutine sub'''

    out, _ = fuse_loops(code, fortran_reader, fortran_writer)
    correct = """
  do jj = 1, n + 1, 1
    do ji = 1, 10, 1
      s(ji,jj) = t(ji,jj) + 1
    enddo
    do ji = 1, 10, 1
      s(ji,jj) = s(ji,jj) + t(jj,jj) + t(ji,ji)
    enddo
  enddo"""
    assert correct in out
    assert Compile(tmpdir).string_compiles(out)

    # This cannot be fused, since 's' is written in the
    # first iteration and read in the second.
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t, u
              do jj=1, n+1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=1, n+1
                 do ji=1, 10
                    u(ji, jj)=s(jj, ji)+1
                 enddo
              enddo
              end subroutine sub'''

    with pytest.raises(TransformationError) as err:
        fuse_loops(code, fortran_reader, fortran_writer)
    assert "Variable 's' is written to in one or both of the loops and the "\
        "loop variable jj is used in different index locations (1 and 0) "\
        "when accessing it." in str(err.value)

    # This cannot be fused, since 's' is read in the
    # first iteration and written in the second with
    # different indices.
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t, u
              do jj=1, n+1
                 do ji=1, 10
                    u(ji, jj)=s(jj, ji)+1
                 enddo
              enddo
              do jj=1, n+1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''

    with pytest.raises(TransformationError) as err:
        fuse_loops(code, fortran_reader, fortran_writer)
    assert "Variable 's' is written to in one or both of the loops and the " \
           "loop variable jj is used in different index locations (0 and 1) " \
           "when accessing it." in str(err.value)
Ejemplo n.º 26
0
def test_fuse_incorrect_bounds_step(tmpdir, fortran_reader, fortran_writer):
    '''
    Test that loop boundaries and step size must be identical.
    '''

    # Lower loop boundary
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=2, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''
    with pytest.raises(TransformationError) as err:
        fuse_loops(code, fortran_reader, fortran_writer)
    assert "Lower loop bounds must be identical, but are" in str(err.value)

    # Upper loop boundary
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=1, n+1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''
    with pytest.raises(TransformationError) as err:
        fuse_loops(code, fortran_reader, fortran_writer)
    assert "Upper loop bounds must be identical, but are" in str(err.value)

    # Test step size:
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=1, n, 2
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''
    with pytest.raises(TransformationError) as err:
        fuse_loops(code, fortran_reader, fortran_writer)
    assert "Step size in loops must be identical, but are" in str(err.value)

    # Test step size - make sure it defaults to 1
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=1, n, 1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''
    out, _ = fuse_loops(code, fortran_reader, fortran_writer)
    assert Compile(tmpdir).string_compiles(out)
Ejemplo n.º 27
0
def test_fuse_ok(tmpdir, fortran_reader, fortran_writer):
    '''This tests verifies that loop fusion can be successfully applied to
    conformant loops.

    '''
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=1, n
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''
    out, psyir = fuse_loops(code, fortran_reader, fortran_writer)

    expected = """  do jj = 1, n, 1
    do ji = 1, 10, 1
      s(ji,jj) = t(ji,jj) + 1
    enddo
    do ji = 1, 10, 1
      s(ji,jj) = t(ji,jj) + 1
    enddo
  enddo"""
    assert expected in out
    assert Compile(tmpdir).string_compiles(out)

    # Then fuse the inner ji loops
    fuse = NemoLoopFuseTrans()
    fuse.apply(psyir[0].loop_body[0], psyir[0].loop_body[1])

    out = fortran_writer(psyir)
    expected = """
  do jj = 1, n, 1
    do ji = 1, 10, 1
      s(ji,jj) = t(ji,jj) + 1
      s(ji,jj) = t(ji,jj) + 1
    enddo
  enddo"""
    assert expected in out
    assert Compile(tmpdir).string_compiles(out)

    # Test more complex loop boundaries. Note that
    # we might actually consider simplifying these
    # expressions
    code = '''subroutine sub()
              integer :: ji, jj, n
              integer, dimension(10,10) :: s, t
              do jj=2-1, n+1-1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              do jj=2-1, n+1-1
                 do ji=1, 10
                    s(ji, jj)=t(ji, jj)+1
                 enddo
              enddo
              end subroutine sub'''
    out, _ = fuse_loops(code, fortran_reader, fortran_writer)
    expected = """  do jj = 2 - 1, n + 1 - 1, 1
    do ji = 1, 10, 1
      s(ji,jj) = t(ji,jj) + 1
    enddo
    do ji = 1, 10, 1
      s(ji,jj) = t(ji,jj) + 1
    enddo
  enddo"""
    assert expected in out
    assert Compile(tmpdir).string_compiles(out)