示例#1
0
def test_access_info():
    '''Test the AccessInfo class.
    '''
    location = 12
    access_info = AccessInfo(AccessType.READ, location, Node())
    assert access_info.access_type == AccessType.READ
    assert access_info.location == location
    assert access_info.indices is None
    assert str(access_info) == "READ(12)"
    access_info.change_read_to_write()
    assert str(access_info) == "WRITE(12)"
    assert access_info.access_type == AccessType.WRITE
    with pytest.raises(InternalError) as err:
        access_info.change_read_to_write()
    assert "Trying to change variable to 'WRITE' which does not have "\
        "'READ' access." in str(err.value)

    access_info.indices = ["i"]
    assert access_info.indices == ["i"]

    access_info = AccessInfo(AccessType.UNKNOWN, location, Node())
    assert access_info.access_type == AccessType.UNKNOWN
    assert access_info.location == location
    assert access_info.indices is None

    access_info = AccessInfo(AccessType.UNKNOWN, location, Node(), ["i", "j"])
    assert access_info.access_type == AccessType.UNKNOWN
    assert access_info.location == location
    assert access_info.indices == ["i", "j"]
示例#2
0
def test_variable_access_info_read_write():
    '''Test the handling of READWRITE accesses. A READWRITE indicates both
    a read and a write access, but if a variable as a READ and a WRITE
    access, this is not one READWRITE access. A READWRITE access is only
    used in subroutine calls (depending on kernel metadata)
    '''

    vai = VariableAccessInfo("var_name")
    assert vai.has_read_write() is False

    # Add a READ and WRITE access at the same location, and make sure it
    # is not reported as READWRITE access
    node = Node()
    vai.add_access(AccessType.READ, 2, node)
    assert vai[0].node == node
    assert vai[0].location == 2
    vai.add_access(AccessType.WRITE, 2, Node())
    assert vai.has_read_write() is False

    vai.add_access(AccessType.READWRITE, 2, Node())
    assert vai.has_read_write()

    # Create a new instance, and add only one READWRITE access:
    vai = VariableAccessInfo("var_name")
    vai.add_access(AccessType.READWRITE, 2, Node())
    assert vai.has_read_write()
    assert vai.is_read()
    assert vai.is_written()
示例#3
0
def test_variables_access_info():
    '''Test the implementation of VariablesAccessInfo, a class that manages
    a list of variables, each with a list of accesses.
    '''
    var_accesses = VariablesAccessInfo()
    node1 = Node()
    var_accesses.add_access(Signature("read"), AccessType.READ, node1)
    node2 = Node()
    var_accesses.add_access(Signature("written"), AccessType.WRITE, node2)
    assert str(var_accesses) == "read: READ, written: WRITE"

    var_accesses.next_location()
    node = Node()
    var_accesses.add_access(Signature("written"), AccessType.WRITE, node)
    var_accesses.next_location()
    var_accesses.add_access(Signature("read_written"), AccessType.WRITE, node)
    var_accesses.add_access(Signature("read_written"), AccessType.READ, node)
    assert str(var_accesses) == "read: READ, read_written: READ+WRITE, "\
                                "written: WRITE"
    assert set(var_accesses.all_signatures) == set(
        [Signature("read"),
         Signature("written"),
         Signature("read_written")])
    all_accesses = var_accesses[Signature("read")].all_accesses
    assert all_accesses[0].node == node1
    written_accesses = var_accesses[Signature("written")].all_accesses
    assert written_accesses[0].location == 0
    assert written_accesses[1].location == 1
    # Check that the location pointer is pointing to the next statement:
    assert var_accesses.location == 2

    # Create a new instance
    var_accesses2 = VariablesAccessInfo()
    var_accesses2.add_access(Signature("new_var"), AccessType.READ, node)
    var_accesses2.add_access(Signature("written"), AccessType.READ, node)

    # Now merge the new instance with the previous instance:
    var_accesses.merge(var_accesses2)
    assert str(var_accesses) == "new_var: READ, read: READ, " \
                                "read_written: READ+WRITE, written: READ+WRITE"

    with pytest.raises(KeyError):
        _ = var_accesses[Signature("does_not_exist")]
    with pytest.raises(KeyError):
        var_accesses.is_read(Signature("does_not_exist"))
    with pytest.raises(KeyError):
        var_accesses.is_written(Signature("does_not_exist"))

    assert "READWRITE" not in str(var_accesses)
    var_accesses.add_access(Signature("readwrite"), AccessType.READWRITE, node)
    assert "READWRITE" in str(var_accesses)

    with pytest.raises(InternalError) as err:
        var_accesses.add_access("no-signature", AccessType.READWRITE, node)

    assert "Got 'no-signature' of type 'str' but expected it to be of type " \
           "psyclone.core.Signature." in str(err.value)
示例#4
0
def test_omploop_no_collapse():
    ''' Check that the OMPLoopTrans.directive() method rejects the
    collapse argument '''
    from psyclone.transformations import OMPLoopTrans
    trans = OMPLoopTrans()
    pnode = Node()
    cnode = Node()
    with pytest.raises(NotImplementedError) as err:
        _ = trans._directive(pnode, cnode, collapse=2)
    assert ("The COLLAPSE clause is not yet supported for '!$omp do' "
            "directives" in str(err.value))
示例#5
0
def test_malformed_extract_node(monkeypatch):
    ''' Check that we raise the expected error if a ReadOnlyVerifyNode does
    not have a single Schedule node as its child. '''
    read_node = ReadOnlyVerifyNode()
    monkeypatch.setattr(read_node, "_children", [])
    with pytest.raises(InternalError) as err:
        _ = read_node.read_only_verify_body
    assert "malformed or incomplete. It should have a " in str(err.value)
    monkeypatch.setattr(read_node, "_children", [Node(), Node()])
    with pytest.raises(InternalError) as err:
        _ = read_node.read_only_verify_body
    assert "malformed or incomplete. It should have a " in str(err.value)
示例#6
0
def test_malformed_profile_node(monkeypatch):
    ''' Check that we raise the expected error if a ProfileNode does not have
    a single Schedule node as its child. '''
    pnode = ProfileNode()
    monkeypatch.setattr(pnode, "_children", [])
    with pytest.raises(InternalError) as err:
        _ = pnode.profile_body
    assert "malformed or incomplete. It should have a " in str(err.value)
    monkeypatch.setattr(pnode, "_children", [Node(), Node()])
    with pytest.raises(InternalError) as err:
        _ = pnode.profile_body
    assert "malformed or incomplete. It should have a " in str(err.value)
示例#7
0
def test_variable_access_info_is_array():
    '''Test that the SingleVariableAccesInfo class handles arrays as expected.

    '''

    vai = SingleVariableAccessInfo("var_name")
    # Add non array-like access:
    vai.add_access_with_location(AccessType.READ, 1, Node())
    assert not vai.is_array()
    # Add array access:
    vai.add_access_with_location(AccessType.READ, 1, Node(), [[Node()]])
    assert vai.is_array()
示例#8
0
def test_variables_access_info():
    '''Test the implementation of VariablesAccessInfo, a class that manages
    a list of variables, each with a list of accesses.
    '''
    var_accesses = VariablesAccessInfo()
    node1 = Node()
    var_accesses.add_access("read", AccessType.READ, node1)
    node2 = Node()
    var_accesses.add_access("written", AccessType.WRITE, node2)
    assert str(var_accesses) == "read: READ, written: WRITE"

    var_accesses.next_location()
    node = Node()
    var_accesses.add_access("written", AccessType.WRITE, node)
    var_accesses.next_location()
    var_accesses.add_access("read_written", AccessType.WRITE, node)
    var_accesses.add_access("read_written", AccessType.READ, node)
    assert str(var_accesses) == "read: READ, read_written: READ+WRITE, "\
                                "written: WRITE"
    assert set(var_accesses.all_vars) == set(
        ["read", "written", "read_written"])
    all_accesses = var_accesses["read"].all_accesses
    assert all_accesses[0].node == node1
    written_accesses = var_accesses["written"].all_accesses
    assert written_accesses[0].location == 0
    assert written_accesses[1].location == 1
    # Check that the location pointer is pointing to the next statement:
    assert var_accesses.location == 2

    # Create a new instance
    var_accesses2 = VariablesAccessInfo()
    var_accesses2.add_access("new_var", AccessType.READ, node)
    var_accesses2.add_access("written", AccessType.READ, node)

    # Now merge the new instance with the previous instance:
    var_accesses.merge(var_accesses2)
    assert str(var_accesses) == "new_var: READ, read: READ, " \
                                "read_written: READ+WRITE, written: READ+WRITE"

    with pytest.raises(KeyError):
        _ = var_accesses["does_not_exist"]
    with pytest.raises(KeyError):
        var_accesses.is_read("does_not_exist")
    with pytest.raises(KeyError):
        var_accesses.is_written("does_not_exist")

    assert "READWRITE" not in str(var_accesses)
    var_accesses.add_access("readwrite", AccessType.READWRITE, node)
    assert "READWRITE" in str(var_accesses)
示例#9
0
def test_access_info_exceptions():
    '''Test that the right exceptions are raised.
    '''
    location = 12
    with pytest.raises(InternalError) as err:
        _ = AccessInfo(AccessType.READ, location, Node(),
                       component_indices=123)
    assert "component_indices in add_access must be a list of lists or " \
           "None, got '123'" in str(err.value)

    with pytest.raises(InternalError) as err:
        _ = AccessInfo(AccessType.READ, location, Node(),
                       component_indices=[[], 123])
    assert "component_indices in add_access must be a list of lists or None, "\
        "got '[[], 123]'" in str(err.value)
示例#10
0
def test_get_node_list():
    '''Test for valid parameters to get_node_list.'''

    my_rt = MyRegionTrans()
    # 1) Provide a schedule
    # ---------------------
    sched = Schedule()
    # get_node_list returns a copy of the list, so it must be a list
    # with the same content, but NOT the same list:
    node_list = my_rt.get_node_list(sched)
    assert sched.children == node_list
    assert node_list is not sched.children

    # 2) Provide a single node
    # ------------------------
    node = Node()
    node_list = my_rt.get_node_list(node)
    assert node_list == [node]

    # 3) Provide a node list
    # ----------------------
    # We use the previously returned node list, and make sure
    # that we get a copy of that list.
    node_list2 = my_rt.get_node_list(node_list)
    assert node_list2 == node_list
    assert node_list2 is not node_list
示例#11
0
def test_check_intergrid():
    ''' Test that the check_intergrid utility does not raise an error if the
    supplied node has no children. '''
    from psyclone.psyir.nodes import Node
    from psyclone.transformations import check_intergrid
    tnode = Node()
    check_intergrid(tnode)
示例#12
0
def test_psyirvisitor_visit_no_method2():
    '''Check that an exception is not raised if the method for the Node class
    does not exist and skip_nodes is set to True.

    '''
    visitor = PSyIRVisitor(skip_nodes=True)
    result = visitor(Node())
    assert result is None
示例#13
0
def test_kernelfunctor_parent():
    '''Check that the optional parent argument to a KernelFunctor class
    constructor is stored correctly.

    '''
    parent = Node()
    symbol = DataTypeSymbol("hello", StructureType())
    klr = KernelFunctor(symbol, parent=parent)
    assert klr.parent == parent
示例#14
0
def test_variable_access_info():
    '''Test the VariableAccesInfo class, i.e. the class that manages a list
    of VariableInfo instances for one variable
    '''

    vai = VariableAccessInfo("var_name")
    assert vai.var_name == "var_name"
    assert str(vai) == "var_name:"
    assert vai.is_written() is False
    assert vai.is_read() is False
    assert vai.all_accesses == []

    vai.add_access(AccessType.READ, 2, Node())
    assert str(vai) == "var_name:READ(2)"
    assert vai.is_read()
    assert vai.is_read_only()
    vai.change_read_to_write()
    assert not vai.is_read()
    assert vai.is_written()
    assert not vai.is_read_only()

    # Now we have one write access, which we should not be able to
    # change to write again:
    with pytest.raises(InternalError) as err:
        vai.change_read_to_write()
    assert "Trying to change variable 'var_name' to 'WRITE' which "\
        "does not have 'READ' access." in str(err.value)

    assert vai.all_accesses[0] == vai[0]
    with pytest.raises(IndexError) as err:
        _ = vai[1]

    # Add a READ access - now we should not be able to
    # change read to write anymore:
    vai.add_access(AccessType.READ, 1, Node())
    with pytest.raises(InternalError) as err:
        vai.change_read_to_write()
    assert "Variable 'var_name' had 2 accesses listed, "\
           "not one in change_read_to_write." in str(err.value)

    # And make sure the variable is not read_only if a write is added
    vai.add_access(AccessType.WRITE, 3, Node())
    assert vai.is_read_only() is False
示例#15
0
def test_psyirvisitor_visit_no_method1():
    '''Check that an exception is raised if the method for the Node class
    does not exist.

    '''
    visitor = PSyIRVisitor()
    with pytest.raises(VisitorError) as excinfo:
        visitor(Node())
    assert ("Visitor Error: Unsupported node 'Node' found: method names "
            "attempted were ['node_node']." in str(excinfo.value))
示例#16
0
def test_instance_args():
    '''Check that the parent and variable arguments are stored correctly
    when values are provided.

    '''
    variable = DataSymbol("nemo_symbol", INTEGER_TYPE)
    parent = Node()
    nemo_loop = NemoLoop(parent=parent, variable=variable)
    assert nemo_loop.parent is parent
    assert nemo_loop._variable is variable
示例#17
0
def test_accloop():
    ''' Generic tests for the ACCLoopTrans transformation class '''
    from psyclone.transformations import ACCLoopTrans
    from psyclone.psyGen import ACCLoopDirective
    trans = ACCLoopTrans()
    assert trans.name == "ACCLoopTrans"
    assert str(trans) == "Adds an 'OpenACC loop' directive to a loop"

    pnode = Node()
    cnode = Statement()
    tdir = trans._directive(pnode, [cnode])
    assert isinstance(tdir, ACCLoopDirective)
示例#18
0
def test_lfricalgorithminvokecall_options():
    '''Check that an instance of LFRicAlgorithmInvokeCall can be created
    with optional arguments and that these optional arguments are
    stored as expected.

    '''
    node = Node()
    routine = RoutineSymbol("hello")
    call = LFRicAlgorithmInvokeCall(
        routine, 0, description="describing an invoke", parent=node)
    assert call._description == "describing an invoke"
    assert call.parent is node
示例#19
0
def test_variables_access_info_merge():
    '''Tests the merge operation of VariablesAccessInfo.
    '''
    # First create one instance representing for example:
    # a=b; c=d
    var_accesses1 = VariablesAccessInfo()
    node = Node()
    var_accesses1.add_access("b", AccessType.READ, node)
    var_accesses1.add_access("a", AccessType.WRITE, node)
    var_accesses1.next_location()
    var_accesses1.add_access("d", AccessType.READ, node)
    var_accesses1.add_access("c", AccessType.WRITE, node)
    c_accesses = var_accesses1["c"]
    assert len(c_accesses.all_accesses) == 1
    assert c_accesses[0].access_type == AccessType.WRITE

    # First create one instance representing for example:
    # e=f; g=h
    var_accesses2 = VariablesAccessInfo()
    var_accesses2.add_access("f", AccessType.READ, node)
    var_accesses2.add_access("e", AccessType.WRITE, node)
    var_accesses2.next_location()
    var_accesses2.add_access("h", AccessType.READ, node)
    var_accesses2.add_access("g", AccessType.WRITE, node)

    # Now merge the second instance into the first one
    var_accesses1.merge(var_accesses2)

    # The e=f access pattern should have the same location
    # as the c=d (since there is no next_location after
    # adding the b=a access):
    c_accesses = var_accesses1["c"]
    e_accesses = var_accesses1["e"]
    assert c_accesses[0].access_type == AccessType.WRITE
    assert e_accesses[0].access_type == AccessType.WRITE
    assert c_accesses[0].location == e_accesses[0].location

    # Test that the g=h part has a higher location than the
    # c=d data. This makes sure that merge() increases the
    # location number of accesses when merging.
    c_accesses = var_accesses1["c"]
    g_accesses = var_accesses1["g"]
    h_accesses = var_accesses1["h"]
    assert c_accesses[0].location < g_accesses[0].location
    assert g_accesses[0].location == h_accesses[0].location

    # Also make sure that the access location was properly increased
    # Originally we had locations 0,1. Then we merged accesses with
    # location 0,1 in - the one at 0 is merged with the current 1,
    # and the new location 1 increases the current location from
    # 1 to 2:
    assert var_accesses1.location == 2
def test_validate():
    '''Test that the validate method in the ArrayRange2LoopTrans class
    raises the expected exceptions.

    '''
    trans = ArrayRange2LoopTrans()
    with pytest.raises(TransformationError) as info:
        trans.validate(Node())
    assert (
        "Error in ArrayRange2LoopTrans transformation. The supplied node "
        "argument should be a PSyIR Assignment, but found 'Node'."
        in str(info.value))

    with pytest.raises(TransformationError) as info:
        trans.validate(Assignment.create(DataNode(), DataNode()))
    assert (
        "Error in ArrayRange2LoopTrans transformation. The lhs of the "
        "supplied Assignment node should be a PSyIR ArrayReference, but found "
        "'DataNode'." in str(info.value))

    array_symbol = DataSymbol("x", ArrayType(INTEGER_TYPE, [10, 10]))
    one = Literal("1", INTEGER_TYPE)
    array_assignment = ArrayReference.create(array_symbol, [one, one.copy()])
    with pytest.raises(TransformationError) as info:
        trans.validate(Assignment.create(array_assignment, DataNode()))
    assert (
        "Error in ArrayRange2LoopTrans transformation. The lhs of the "
        "supplied Assignment node should be a PSyIR ArrayReference with at "
        "least one "
        "of its dimensions being a Range, but found None in "
        "'ArrayReference[name:'x']\\nLiteral[value:'1', "
        "Scalar<INTEGER, UNDEFINED>]\\nLiteral[value:'1', Scalar<INTEGER, "
        "UNDEFINED>]\\n'." in str(info.value))

    array_x = create_array_x(SymbolTable())
    assignment = Assignment.create(
        create_array_x(SymbolTable()), array_x)
    trans.validate(assignment)

    array_x.children[0].step = Literal("2", INTEGER_TYPE)
    with pytest.raises(TransformationError) as info:
        trans.validate(assignment)
    assert (
        "The ArrayRange2LoopTrans transformation only supports ranges that "
        "are known to be the same as each other but array access 'x' "
        "dimension 0 and 'x' dimension 0 are either different or can't be "
        "determined in the assignment 'Assignment[]\\n"
        "ArrayReference[name:'x']\\nRange[]\\n"
        "ArrayReference[name:'x']\\nRange[]\\n'."
        in str(info.value))
示例#21
0
def test_get_literal_precision_type(monkeypatch):
    '''Make sure the get_literal_precision function in fparser2.py behaves
    as expected when an unsupported datatype is found

    '''
    monkeypatch.setattr(fparser2, "CONSTANT_TYPE_MAP", {})
    code = "x=0.0"
    reader = FortranStringReader(code)
    astmt = Fortran2003.Assignment_Stmt(reader)
    fparser2_literal = astmt.children[2]
    with pytest.raises(NotImplementedError) as excinfo:
        _ = get_literal_precision(fparser2_literal, Node())
    assert ("Could not process Real_Literal_Constant. Only 'real', 'integer', "
            "'logical' and 'character' intrinsic types are supported."
            in str(excinfo.value))
示例#22
0
def test_range_init(parser):
    ''' Check that the Range constructor behaves as intended. '''
    from fparser.common.readfortran import FortranStringReader
    # When no arguments are provided
    erange = Range()
    assert not erange.children  # Children list is empty
    assert erange.parent is None
    assert erange.annotations == []
    assert erange.ast is None
    # When arguments are provided
    parent = Node()
    reader = FortranStringReader("program hello\nend program hello\n")
    prog = parser(reader)
    erange2 = Range(ast=prog, parent=parent)
    assert erange2.parent is parent
    assert erange2.ast is prog
    with pytest.raises(InternalError) as err:
        _ = Range(annotations=["was-where"])
    assert "unrecognised annotation 'was-where'" in str(err.value)
示例#23
0
def test_psyirvisitor_visit_attribute_error():
    '''Check that an Attribute Error is raised if the method for the Node
    class does exist and the method itself raises an Attribute
    Error. This is checked because AttributeError is used to catch a
    method not existing. Therefore an AttributeError raised by a
    method that does exist could be mistaken as meaning that the
    method does not exist.

    '''
    class MyPSyIRVisitor(PSyIRVisitor):
        '''Subclass PSyIRVisitor to make the node method exist but it itself
        raises an attribute error.'''
        def node_node(self, _):
            ''' Raise an AttributeError for testing purposes '''
            raise AttributeError("Error")

    visitor = MyPSyIRVisitor()
    with pytest.raises(AttributeError) as excinfo:
        _ = visitor(Node())
    assert str(excinfo.value) == "Error"
示例#24
0
def test_range_create():
    ''' Check that the Range.create() method behaves as intended. '''
    parent = Node()
    start = Literal("1", INTEGER_SINGLE_TYPE)
    stop = Literal("10", INTEGER_SINGLE_TYPE)
    # No parent and no step
    erange = Range.create(start, stop)
    assert erange.children[0] is start
    assert erange.children[1] is stop
    assert erange.parent is None
    # Parent but no step
    erange2 = Range.create(start, stop, parent=parent)
    assert erange2.parent is parent
    assert erange2.children[2].value == "1"
    # Parent and step supplied
    erange3 = Range.create(start,
                           stop,
                           step=Literal("5", INTEGER_SINGLE_TYPE),
                           parent=parent)
    assert erange3.parent is parent
    assert erange3.children[2].value == "5"
示例#25
0
def test_string_compare():
    '''Check that the string_compare utility function in
    ArrayRange2LoopTrans works as expected.

    '''
    with pytest.raises(TypeError) as info:
        ArrayRange2LoopTrans.string_compare(None, None)
    assert ("The first argument to the string_compare method should be a Node "
            "but found 'NoneType'." in str(info.value))

    with pytest.raises(TypeError) as info:
        ArrayRange2LoopTrans.string_compare(Node(), None)
    assert (
        "The second argument to the string_compare method should be a Node "
        "but found 'NoneType'." in str(info.value))

    node1 = Literal("1.0", REAL_TYPE)
    node2 = BinaryOperation.create(BinaryOperation.Operator.MUL, node1, node1)
    node3 = BinaryOperation.create(BinaryOperation.Operator.MAX, node2, node2)
    assert ArrayRange2LoopTrans.string_compare(node3, node3) is True
    assert ArrayRange2LoopTrans.string_compare(node3, node2) is False
示例#26
0
def test_check_intergrid():
    ''' Test that the check_intergrid utility does not raise an error if the
    supplied node has no children. '''
    tnode = Node()
    check_intergrid(tnode)
示例#27
0
    '''We can't create an instance of RegionTrans since it is
    abstract, so create a simple class that can be instantiated
    by adding dummy implementations of the missing methods.
    '''
    excluded_node_types = ()

    def apply(self, node, options=None):
        '''Dummy only to make this not abstract.'''

    @property
    def name(self):
        '''Dummy only to make this not abstract.'''


# -----------------------------------------------------------------------------
@pytest.mark.parametrize("node_list", [5, [1], [1, Node()],
                                       [Node(), 1], [Node(), Node(), 1],
                                       [Node(), 1, Node()]])
def test_get_node_list_errors(node_list):
    '''Test incorrect parameters to get_node_list.
    '''
    my_rt = MyRegionTrans()
    with pytest.raises(TransformationError) as err:
        my_rt.get_node_list(node_list)
    assert "Argument must be a single Node in a Schedule, a Schedule or a "\
           "list of Nodes in a Schedule" in str(err.value)

    # Test for more specific error message for the first test case:
    # node_list = 5
    if isinstance(node_list, int):
        # Python 3 reports 'class', python 2 'type' - so just check for both