Ejemplo n.º 1
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.º 2
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.º 3
0
def test_oclw_gen_id_variable():
    '''Check the OpenCLWriter class gen_id_variables method produces
    the expected declarations.

    '''
    oclwriter = OpenCLWriter()
    symbol = Symbol("id1", "integer")
    result = oclwriter.gen_id_variable(symbol, 3)
    assert result == "int id1 = get_global_id(3);\n"

    symbol = Symbol("array", "integer", shape=[2, None, 2])
    with pytest.raises(VisitorError) as excinfo:
        _ = oclwriter.gen_id_variable(symbol, 3)
    assert "OpenCL work-item identifiers must be scalar integer symbols " \
        "but found" in str(excinfo)
Ejemplo n.º 4
0
def test_fw_gen_use(fort_writer):
    '''Check the FortranWriter class gen_use method produces the expected
    declaration. Also check that an exception is raised if the symbol
    does not describe a use statement.

    '''
    symbol = Symbol("dummy1",
                    "deferred",
                    interface=Symbol.FortranGlobal("my_module"))
    result = fort_writer.gen_use(symbol)
    assert result == "use my_module, only : dummy1\n"

    symbol = Symbol("dummy1", "integer")
    with pytest.raises(VisitorError) as excinfo:
        _ = fort_writer.gen_use(symbol)
    assert ("gen_use() requires the symbol interface for symbol 'dummy1' to "
            "be a FortranGlobal instance but found 'NoneType'."
            in str(excinfo.value))
Ejemplo n.º 5
0
def test_oclw_gen_array_length_variables():
    '''Check the OpenCLWriter class gen_array_length_variables method produces
    the expected declarations.

    '''
    oclwriter = OpenCLWriter()

    # A scalar should not return any LEN variables
    symbol1 = Symbol("dummy2LEN1", "integer")
    result = oclwriter.gen_array_length_variables(symbol1)
    assert result == ""

    # Array with 1 dimension generates 1 length variable
    symbol2 = Symbol("dummy1", "integer", shape=[2])
    result = oclwriter.gen_array_length_variables(symbol2)
    assert result == "int dummy1LEN1 = get_global_size(0);\n"

    # Array with multiple dimension generates one variable per dimension
    symbol3 = Symbol("dummy2", "integer", shape=[2, None, 2])
    result = oclwriter.gen_array_length_variables(symbol3)
    assert result == "int dummy2LEN1 = get_global_size(0);\n" \
        "int dummy2LEN2 = get_global_size(1);\n" \
        "int dummy2LEN3 = get_global_size(2);\n"

    # Create a symbol table
    symtab = SymbolTable()
    symtab.add(symbol1)
    symtab.add(symbol2)
    symtab.add(symbol3)

    # If there are no name clashes, generate array length variables.
    result = oclwriter.gen_array_length_variables(symbol2, symtab)
    assert result == "int dummy1LEN1 = get_global_size(0);\n"

    with pytest.raises(VisitorError) as excinfo:
        _ = oclwriter.gen_array_length_variables(symbol3, symtab)
    assert "Unable to declare the variable 'dummy2LEN1' to store the length " \
        "of 'dummy2' because the Symbol Table already contains a symbol with" \
        " the same name." in str(excinfo)
Ejemplo n.º 6
0
def test_cw_gen_local_variable(monkeypatch):
    '''Check the CWriter class gen_local_variable method produces
    the expected declarations.

    '''
    cwriter = CWriter()

    monkeypatch.setattr(cwriter, "gen_declaration",
                        lambda x: "<declaration>")

    # Local variables are declared as single statements
    symbol = Symbol("dummy1", "integer")
    result = cwriter.gen_local_variable(symbol)
    # Result should include the mocked gen_declaration and ';\n'
    assert result == "<declaration>;\n"
Ejemplo n.º 7
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))
Ejemplo n.º 8
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.º 9
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.º 10
0
def test_symtab_implementation_for_opencl():
    # pylint: disable=invalid-name
    ''' 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.
    # pylint: disable=protected-access
    arg1._datatype = "real"
    # pylint: enable=protected-access
    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)

    # pylint: disable=protected-access
    arg1._datatype = "integer"  # restore
    arg2._shape = [None]
    # pylint: enable=protected-access
    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.º 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)