Ejemplo n.º 1
0
def test_fw_gen_declaration():
    '''Check the FortranWriter class gen_declaration method produces
    the expected declarations.

    '''
    fvisitor = FortranWriter()

    # Basic entry
    symbol = Symbol("dummy1", "integer")
    result = fvisitor.gen_declaration(symbol)
    assert result == "integer(i_def) :: dummy1\n"

    # Array with intent
    symbol = Symbol("dummy2", "integer", shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.READ))
    result = fvisitor.gen_declaration(symbol)
    assert result == "integer(i_def), dimension(2,:,2), intent(in) :: dummy2\n"

    # Array with unknown intent
    symbol = Symbol("dummy2", "integer", shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    result = fvisitor.gen_declaration(symbol)
    assert result == "integer(i_def), dimension(2,:,2) :: dummy2\n"

    # Constant
    symbol = Symbol("dummy3", "integer", constant_value=10)
    result = fvisitor.gen_declaration(symbol)
    assert result == "integer(i_def), parameter :: dummy3 = 10\n"
Ejemplo n.º 2
0
def test_symtab_implementation_for_opencl():
    ''' Tests that the GOcean specialised Symbol Table implements the
    abstract properties needed to generate OpenCL.
    '''
    kschedule = GOKernelSchedule('test')

    # Test symbol table without any kernel argument
    with pytest.raises(GenerationError) as err:
        _ = kschedule.symbol_table.iteration_indices
    assert ("GOcean 1.0 API kernels should always have at least two "
            "arguments representing the iteration indices but the Symbol "
            "Table for kernel 'test' has only 0 argument(s).") in str(err)

    # Test symbol table with 1 kernel argument
    arg1 = Symbol("arg1", "integer", [],
                  interface=Symbol.Argument(access=Symbol.Access.READ))
    kschedule.symbol_table.add(arg1)
    kschedule.symbol_table.specify_argument_list([arg1])
    with pytest.raises(GenerationError) as err:
        _ = kschedule.symbol_table.iteration_indices
    assert ("GOcean 1.0 API kernels should always have at least two "
            "arguments representing the iteration indices but the Symbol "
            "Table for kernel 'test' has only 1 argument(s).") in str(err)

    # Test symbol table with 2 kernel argument
    arg2 = Symbol("arg2", "integer", shape=[],
                  interface=Symbol.Argument(access=Symbol.Access.READ))
    kschedule.symbol_table.add(arg2)
    kschedule.symbol_table.specify_argument_list([arg1, arg2])
    iteration_indices = kschedule.symbol_table.iteration_indices
    assert iteration_indices[0] is arg1
    assert iteration_indices[1] is arg2

    # Test symbol table with 3 kernel argument
    arg3 = Symbol("buffer1", "real", shape=[10, 10],
                  interface=Symbol.Argument(access=Symbol.Access.READ))
    kschedule.symbol_table.add(arg3)
    kschedule.symbol_table.specify_argument_list([arg1, arg2, arg3])
    iteration_indices = kschedule.symbol_table.iteration_indices
    data_args = kschedule.symbol_table.data_arguments
    assert iteration_indices[0] is arg1
    assert iteration_indices[1] is arg2
    assert data_args[0] is arg3

    # Test gen_ocl with wrong iteration indices types and shapes.
    arg1._datatype = "real"
    with pytest.raises(GenerationError) as err:
        _ = kschedule.symbol_table.iteration_indices
    assert ("GOcean 1.0 API kernels first argument should be a scalar integer"
            " but got a scalar of type 'real' for kernel 'test'.")\
        in str(err)

    arg1._datatype = "integer"  # restore
    arg2._shape = [None]
    with pytest.raises(GenerationError) as err:
        _ = kschedule.symbol_table.iteration_indices
    assert ("GOcean 1.0 API kernels second argument should be a scalar integer"
            " but got an array of type 'integer' for kernel 'test'.")\
        in str(err)
Ejemplo n.º 3
0
def test_gen_dims():
    '''Check the gen_dims function produces the expected dimension
    strings.

    '''
    arg = Symbol("arg", "integer",
                 interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    symbol = Symbol("dummy", "integer", shape=[arg, 2, None],
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    assert gen_dims(symbol) == ["arg", "2", ":"]
Ejemplo n.º 4
0
def test_oclw_gen_declaration():
    '''Check the OpenCLWriter class gen_declaration method produces
    the expected declarations.

    '''
    oclwriter = OpenCLWriter()

    # Basic entry - Scalar are passed by value and don't have additional
    # qualifiers.
    symbol = Symbol("dummy1", "integer")
    result = oclwriter.gen_declaration(symbol)
    assert result == "int dummy1"

    # Array argument has a memory qualifier (only __global for now)
    symbol = Symbol("dummy2", "integer", shape=[2, None, 2])
    result = oclwriter.gen_declaration(symbol)
    assert result == "__global int * restrict dummy2"

    # Array with unknown intent
    symbol = Symbol("dummy2",
                    "integer",
                    shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    result = oclwriter.gen_declaration(symbol)
    assert result == "__global int * restrict dummy2"
Ejemplo n.º 5
0
def test_gen_intent():
    '''Check the gen_intent function produces the expected intent
    strings.

    '''
    symbol = Symbol("dummy", "integer",
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    assert gen_intent(symbol) is None
    symbol = Symbol("dummy", "integer",
                    interface=Symbol.Argument(Symbol.Access.READ))
    assert gen_intent(symbol) == "in"
    symbol = Symbol("dummy", "integer",
                    interface=Symbol.Argument(Symbol.Access.WRITE))
    assert gen_intent(symbol) == "out"
    symbol = Symbol("dummy", "integer",
                    interface=Symbol.Argument(Symbol.Access.READWRITE))
    assert gen_intent(symbol) == "inout"
Ejemplo n.º 6
0
def test_oclw_kernelschedule():
    '''Check the OpenCLWriter class kernelschedule_node visitor produces
    the expected C code.

    '''

    # The kernelschedule OpenCL Backend relies on abstrct methods that
    # need to be implemented by the APIs. A generic kernelschedule will
    # produce a NotImplementedError.
    oclwriter = OpenCLWriter()
    kschedule = KernelSchedule("kname")
    with pytest.raises(NotImplementedError) as error:
        _ = oclwriter(kschedule)
    assert "Abstract property. Which symbols are data arguments is " \
        "API-specific." in str(error)

    # Mock abstract properties. (pytest monkeypatch does not work
    # with properties, used sub-class instead)
    class MockSymbolTable(SymbolTable):
        ''' Mock needed abstract methods of the Symbol Table '''
        @property
        def iteration_indices(self):
            return self.argument_list[:2]

        @property
        def data_arguments(self):
            return self.argument_list[2:]
    kschedule.symbol_table.__class__ = MockSymbolTable

    # Create a sample symbol table and kernel schedule
    interface = Symbol.Argument(access=Symbol.Access.UNKNOWN)
    i = Symbol('i', 'integer', interface=interface)
    j = Symbol('j', 'integer', interface=interface)
    data1 = Symbol('data1', 'real', [10, 10], interface=interface)
    data2 = Symbol('data2', 'real', [10, 10], interface=interface)
    kschedule.symbol_table.add(i)
    kschedule.symbol_table.add(j)
    kschedule.symbol_table.add(data1)
    kschedule.symbol_table.add(data2)
    kschedule.symbol_table.specify_argument_list([i, j, data1, data2])
    kschedule.addchild(Return(parent=kschedule))

    result = oclwriter(kschedule)
    print(result)
    assert result == "" \
        "__kernel void kname(\n" \
        "  __global double * restrict data1,\n" \
        "  __global double * restrict data2\n" \
        "  ){\n" \
        "  int data1LEN1 = get_global_size(0);\n" \
        "  int data1LEN2 = get_global_size(1);\n" \
        "  int data2LEN1 = get_global_size(0);\n" \
        "  int data2LEN2 = get_global_size(1);\n" \
        "  int i = get_global_id(0);\n" \
        "  int j = get_global_id(1);\n" \
        "  return;\n" \
        "}\n"
Ejemplo n.º 7
0
def test_gen_kind():
    '''Check the gen_kind function produces the expected kind values. Note
    these are currently hardcoded to support the LFRic API. Issue #375
    captures this problem.

    '''
    int_symbol = Symbol(
        "dummy1", "integer",
        interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    real_symbol = Symbol(
        "dummy2", "real",
        interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    logical_symbol = Symbol(
        "dummy3", "boolean",
        interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))

    assert gen_kind(int_symbol) == "i_def"
    assert gen_kind(real_symbol) == "r_def"
    assert gen_kind(logical_symbol) is None
Ejemplo n.º 8
0
def test_gen_dims_error(monkeypatch):
    '''Check the gen_dims function raises an exception if a symbol shape
    entry is not supported.

    '''
    symbol = Symbol("dummy", "integer",
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    monkeypatch.setattr(symbol, "_shape", ["invalid"])
    with pytest.raises(NotImplementedError) as excinfo:
        _ = gen_dims(symbol)
    assert "unsupported gen_dims index 'invalid'" in str(excinfo)
Ejemplo n.º 9
0
def test_gen_intent_error(monkeypatch):
    '''Check the gen_intent function raises an exception if an unsupported
    access type is found.

    '''
    symbol = Symbol("dummy", "integer",
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    monkeypatch.setattr(symbol.interface, "_access", "UNSUPPORTED")
    with pytest.raises(VisitorError) as excinfo:
        _ = gen_intent(symbol)
    assert "Unsupported access ''UNSUPPORTED'' found." in str(excinfo)
Ejemplo n.º 10
0
def test_fw_gen_vardecl(fort_writer):
    '''Check the FortranWriter class gen_vardecl method produces the
    expected declarations. Also check that an exception is raised if
    the symbol does not describe a variable declaration statement.

    '''
    # Basic entry
    symbol = Symbol("dummy1", "integer")
    result = fort_writer.gen_vardecl(symbol)
    assert result == "integer :: dummy1\n"

    # Array with intent
    symbol = Symbol("dummy2",
                    "integer",
                    shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.READ))
    result = fort_writer.gen_vardecl(symbol)
    assert result == "integer, dimension(2,:,2), intent(in) :: dummy2\n"

    # Array with unknown intent
    symbol = Symbol("dummy2",
                    "integer",
                    shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    result = fort_writer.gen_vardecl(symbol)
    assert result == "integer, dimension(2,:,2) :: dummy2\n"

    # Constant
    symbol = Symbol("dummy3", "integer", constant_value=10)
    result = fort_writer.gen_vardecl(symbol)
    assert result == "integer, parameter :: dummy3 = 10\n"

    # Use statement
    symbol = Symbol("dummy1",
                    "deferred",
                    interface=Symbol.FortranGlobal("my_module"))
    with pytest.raises(VisitorError) as excinfo:
        _ = fort_writer.gen_vardecl(symbol)
    assert ("gen_vardecl requires the symbol 'dummy1' to be a local "
            "declaration or an argument declaration, but found scope "
            "'global' and interface 'FortranGlobal'." in str(excinfo.value))
Ejemplo n.º 11
0
def test_cw_gen_declaration():
    '''Check the CWriter class gen_declaration method produces
    the expected declarations.

    '''
    cwriter = CWriter()

    # Basic entries
    symbol = Symbol("dummy1", "integer")
    result = cwriter.gen_declaration(symbol)
    assert result == "int dummy1"

    symbol = Symbol("dummy1", "character")
    result = cwriter.gen_declaration(symbol)
    assert result == "char dummy1"

    symbol = Symbol("dummy1", "boolean")
    result = cwriter.gen_declaration(symbol)
    assert result == "bool dummy1"

    # Array argument
    symbol = Symbol("dummy2", "real", shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.READ))
    result = cwriter.gen_declaration(symbol)
    assert result == "double * restrict dummy2"

    # Array with unknown intent
    symbol = Symbol("dummy2", "integer", shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    result = cwriter.gen_declaration(symbol)
    assert result == "int * restrict dummy2"

    # Check invalid datatype produces and error
    symbol._datatype = "invalid"
    with pytest.raises(NotImplementedError) as error:
        _ = cwriter.gen_declaration(symbol)
    assert "Could not generate the C definition for the variable 'dummy2', " \
        "type 'invalid' is currently not supported." in str(error)
Ejemplo n.º 12
0
def test_fw_container_3(fort_writer, monkeypatch):
    '''Check the FortranWriter class raises an exception when a Container
    node contains a symbol table with an argument declaration (as this
    does not make sense).

    '''
    # Generate fparser2 parse tree from Fortran code.
    code = ("module test\n"
            "real :: a\n"
            "contains\n"
            "subroutine tmp()\n"
            "end subroutine tmp\n"
            "end module test")
    schedule = create_schedule(code, "tmp")
    container = schedule.root
    symbol = container.symbol_table.symbols[0]
    assert symbol.name == "a"
    monkeypatch.setattr(symbol, "_interface", Symbol.Argument())

    with pytest.raises(VisitorError) as excinfo:
        _ = fort_writer(container)
    assert ("Arguments are not allowed in this context but this symbol table "
            "contains argument(s): '['a']'." in str(excinfo))
Ejemplo n.º 13
0
def test_gen_decls(fort_writer):
    '''Check the FortranWriter class gen_decls method produces the
    expected declarations. Also check that an exception is raised if
    an 'argument' symbol exists in the supplied symbol table and the
    optional argument 'args_allowed' is set to False.

    '''
    symbol_table = SymbolTable()
    use_statement = Symbol("my_use",
                           "deferred",
                           interface=Symbol.FortranGlobal("my_module"))
    symbol_table.add(use_statement)
    argument_variable = Symbol("arg", "integer", interface=Symbol.Argument())
    symbol_table.add(argument_variable)
    local_variable = Symbol("local", "integer")
    symbol_table.add(local_variable)
    result = fort_writer.gen_decls(symbol_table)
    assert (result == "use my_module, only : my_use\n"
            "integer :: arg\n"
            "integer :: local\n")
    with pytest.raises(VisitorError) as excinfo:
        _ = fort_writer.gen_decls(symbol_table, args_allowed=False)
    assert ("Arguments are not allowed in this context but this symbol table "
            "contains argument(s): '['arg']'." in str(excinfo.value))