Beispiel #1
0
def test_fusetrans_error_not_same_parent():
    ''' Check that we reject attempts to fuse loops which don't share the
    same parent '''

    loop1 = Loop.create(DataSymbol("i", INTEGER_TYPE),
                        Literal("1",
                                INTEGER_TYPE), Literal("10", INTEGER_TYPE),
                        Literal("1", INTEGER_TYPE), [Return()])
    sch1 = Schedule()
    sch1.addchild(loop1)

    sch2 = Schedule()
    loop2 = Loop.create(DataSymbol("j", INTEGER_TYPE),
                        Literal("1",
                                INTEGER_TYPE), Literal("10", INTEGER_TYPE),
                        Literal("1", INTEGER_TYPE), [Return()])

    sch2.addchild(loop2)

    fuse = LoopFuseTrans()

    # Try to fuse loops with different parents
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert ("Error in LoopFuseTrans transformation. Loops do not have the "
            "same parent" in str(err.value))
Beispiel #2
0
def test_return_children_validation():
    '''Test that children added to Return are validated. A Return node does
    not accept any children.

    '''
    return_stmt = Return()
    return_stmt1 = Return()
    with pytest.raises(GenerationError) as excinfo:
        return_stmt.addchild(return_stmt1)
    assert ("Item 'Return' can't be child 0 of 'Return'. Return is a"
            " LeafNode and doesn't accept children.") in str(excinfo.value)
def test_create_loop_validate():
    ''' Check that the validate() method works as expected. '''
    trans = CreateNemoLoopTrans()
    with pytest.raises(TransformationError) as err:
        trans.validate(Return())
    assert ("supplied node should be a PSyIR Loop but found 'Return'" in
            str(err.value))
Beispiel #4
0
def test_create_invokesched_validate():
    ''' Check that the validate() method works as expected. '''
    trans = CreateNemoInvokeScheduleTrans()
    with pytest.raises(TransformationError) as err:
        trans.validate(Return())
    assert ("supplied node should be a PSyIR Routine but found 'Return'"
            in str(err.value))
Beispiel #5
0
def test_node_constructor_with_parent():
    ''' Check that the node constructor parent parameter works as expected. '''
    parent = Schedule()
    wrong_parent = Schedule()

    # By default no parent reference is given
    node = Statement()
    assert node.parent is None
    assert node.has_constructor_parent is False

    # The parent argument can predefine the parent reference
    node = Return(parent=parent)
    assert node.parent is parent
    assert node.has_constructor_parent is True

    # Then only an addition to this predefined parent is accepted
    with pytest.raises(GenerationError) as err:
        wrong_parent.addchild(node)
    assert ("'Schedule' cannot be set as parent of 'Return' because its "
            "constructor predefined the parent reference to a different "
            "'Schedule' node." in str(err.value))

    # Once given the proper parent, it can act as a regular node
    parent.addchild(node)
    assert node.parent is parent
    assert node.has_constructor_parent is False
    wrong_parent.addchild(node.detach())
    assert node.parent is wrong_parent
Beispiel #6
0
def test_lower_to_lang_level_single_node():
    ''' Test the lower_to_language_level() method when a Schedule contains
    a single ProfileNode.

    '''
    Profiler.set_options([Profiler.INVOKES])
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE)
    zero = Literal("0.0", REAL_TYPE)
    one = Literal("1.0", REAL_TYPE)
    assign1 = Assignment.create(Reference(arg1), zero)
    assign2 = Assignment.create(Reference(arg1), one)

    kschedule = KernelSchedule.create(
        "work1", symbol_table, [assign1, assign2, Return()])
    Profiler.add_profile_nodes(kschedule, Loop)
    assert isinstance(kschedule.children[0], ProfileNode)
    assert isinstance(kschedule.children[-1], Return)
    kschedule.lower_to_language_level()
    # The ProfileNode should have been replaced by two CodeBlocks with its
    # children inserted between them.
    assert isinstance(kschedule[0], CodeBlock)
    # The first CodeBlock should have the "profile-start" annotation.
    assert kschedule[0].annotations == ["profile-start"]
    ptree = kschedule[0].get_ast_nodes
    assert len(ptree) == 1
    assert isinstance(ptree[0], Fortran2003.Call_Stmt)
    assert kschedule[1] is assign1
    assert kschedule[2] is assign2
    assert isinstance(kschedule[-2], CodeBlock)
    assert kschedule[-2].annotations == []
    ptree = kschedule[-2].get_ast_nodes
    assert len(ptree) == 1
    assert isinstance(ptree[0], Fortran2003.Call_Stmt)
    assert isinstance(kschedule[-1], Return)
Beispiel #7
0
def test_loop_navigation_properties():
    # pylint: disable=too-many-statements
    ''' Tests the start_expr, stop_expr, step_expr and loop_body
    setter and getter properties.

    '''
    loop = Loop()

    # Properties return an error if the node is incomplete
    error_str = ("Loop is incomplete. It should have exactly 4 "
                 "children, but found")
    with pytest.raises(InternalError) as err:
        _ = loop.start_expr
    assert error_str in str(err.value)

    loop.addchild(Literal("start", INTEGER_SINGLE_TYPE))
    loop.addchild(Literal("stop", INTEGER_SINGLE_TYPE))
    loop.addchild(Literal("step", INTEGER_SINGLE_TYPE))

    # If it's not fully complete, it still returns an error
    with pytest.raises(InternalError) as err:
        _ = loop.start_expr
    assert error_str in str(err.value)
    with pytest.raises(InternalError) as err:
        _ = loop.stop_expr
    assert error_str in str(err.value)
    with pytest.raises(InternalError) as err:
        _ = loop.step_expr
    assert error_str in str(err.value)
    with pytest.raises(InternalError) as err:
        _ = loop.loop_body
    assert error_str in str(err.value)
    with pytest.raises(InternalError) as err:
        loop.start_expr = Literal("invalid", INTEGER_SINGLE_TYPE)
    assert error_str in str(err.value)
    with pytest.raises(InternalError) as err:
        loop.stop_expr = Literal("invalid", INTEGER_SINGLE_TYPE)
    assert error_str in str(err.value)
    with pytest.raises(InternalError) as err:
        loop.step_expr = Literal("invalid", INTEGER_SINGLE_TYPE)
    assert error_str in str(err.value)

    # Check that Getters properties work
    loop.addchild(Schedule(parent=loop))
    loop.loop_body.addchild(Return(parent=loop.loop_body))

    assert loop.start_expr.value == "start"
    assert loop.stop_expr.value == "stop"
    assert loop.step_expr.value == "step"
    assert isinstance(loop.loop_body[0], Return)

    # Test Setters
    loop.start_expr = Literal("newstart", INTEGER_SINGLE_TYPE)
    loop.stop_expr = Literal("newstop", INTEGER_SINGLE_TYPE)
    loop.step_expr = Literal("newstep", INTEGER_SINGLE_TYPE)

    assert loop.start_expr.value == "newstart"
    assert loop.stop_expr.value == "newstop"
    assert loop.step_expr.value == "newstep"
Beispiel #8
0
def test_cw_return():
    '''Check the CWriter class return method correctly prints out the
    C representation.

    '''
    cwriter = CWriter()
    result = cwriter(Return())
    assert "return;\n" in result
Beispiel #9
0
 def lower_to_language_level(self):
     ''' MyDSLNode lowers to a return statement and adds a symbol
     if it is inside an scoping region. '''
     # This will break if this Node does not have a parent with
     # a scope. This is intentional to cause an error during the
     # lowering step.
     self.scope.symbol_table.add(DataSymbol("val", REAL_TYPE))
     self.replace_with(Return())
Beispiel #10
0
def test_cw_ifblock():
    '''Check the CWriter class ifblock method correctly prints out the
    C representation.

    '''
    from psyclone.psyir.nodes import IfBlock

    # Try with just an IfBlock node
    ifblock = IfBlock()
    cwriter = CWriter()
    with pytest.raises(VisitorError) as err:
        _ = cwriter(ifblock)
    assert ("IfBlock malformed or incomplete. It should have "
            "at least 2 children, but found 0." in str(err.value))

    # Add the if condition
    ifblock.addchild(Reference(DataSymbol('a', REAL_TYPE), parent=ifblock))
    with pytest.raises(VisitorError) as err:
        _ = cwriter(ifblock)
    assert ("IfBlock malformed or incomplete. It should have "
            "at least 2 children, but found 1." in str(err.value))

    # Fill the if_body and else_body
    ifblock.addchild(Schedule(parent=ifblock))
    ifblock.addchild(Schedule(parent=ifblock))
    ifblock.if_body.addchild(Return(parent=ifblock.if_body))

    condition = Reference(DataSymbol('b', REAL_TYPE))
    then_content = [Return()]
    else_content = [Return()]
    ifblock2 = IfBlock.create(condition, then_content, else_content)
    ifblock2.parent = ifblock.if_body
    ifblock.else_body.addchild(ifblock2)

    result = cwriter(ifblock)
    assert result == ("if (a) {\n"
                      "  return;\n"
                      "} else {\n"
                      "  if (b) {\n"
                      "    return;\n"
                      "  } else {\n"
                      "    return;\n"
                      "  }\n"
                      "}\n")
Beispiel #11
0
def test_ifblock_can_be_printed():
    '''Test that an IfBlock instance can always be printed (i.e. is
    initialised fully)'''
    condition = Reference(DataSymbol('condition1', BOOLEAN_TYPE))
    then_content = [Return()]
    ifblock = IfBlock.create(condition, then_content)

    assert "If[]\n" in str(ifblock)
    assert "condition1" in str(ifblock)  # Test condition is printed
    assert "Return[]" in str(ifblock)  # Test if_body is printed
Beispiel #12
0
def test_auto_invoke_no_return(capsys):
    ''' Check that using the auto-invoke profiling option does not add any
    profiling if the invoke contains a Return anywhere other than as the
    last statement. '''
    Profiler.set_options([Profiler.INVOKES])
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(
        symbol_type=DataSymbol, datatype=REAL_TYPE)
    zero = Literal("0.0", REAL_TYPE)
    assign1 = Assignment.create(Reference(arg1), zero)
    assign2 = Assignment.create(Reference(arg1), zero.copy())

    # Create Schedule with Return at the start.
    kschedule = KernelSchedule.create(
        "work1", symbol_table, [Return(), assign1, assign2])
    Profiler.add_profile_nodes(kschedule, Loop)
    # No profiling should have been added
    assert not kschedule.walk(ProfileNode)
    _, err = capsys.readouterr()
    assert ("Not adding profiling to routine 'work1' because it contains one "
            "or more Return statements" in err)

    # Create Schedule with Return in the middle.
    kschedule = KernelSchedule.create(
        "work2", symbol_table, [assign1.copy(), Return(), assign2.copy()])
    Profiler.add_profile_nodes(kschedule, Loop)
    # No profiling should have been added
    assert not kschedule.walk(ProfileNode)
    _, err = capsys.readouterr()
    assert ("Not adding profiling to routine 'work2' because it contains one "
            "or more Return statements" in err)

    # Create Schedule with a Return at the end as well as in the middle.
    kschedule = KernelSchedule.create(
        "work3", symbol_table, [assign1.copy(), Return(), assign2.copy(),
                                Return()])
    Profiler.add_profile_nodes(kschedule, Loop)
    # No profiling should have been added
    assert not kschedule.walk(ProfileNode)
    _, err = capsys.readouterr()
    assert ("Not adding profiling to routine 'work3' because it contains one "
            "or more Return statements" in err)
Beispiel #13
0
def test_datasymbol_constant_value_setter_invalid():
    '''Test that a DataSymbol constant value setter raises the appropriate
    error if an invalid value and/or datatype are given.'''

    # Test with invalid constant values
    sym = DataSymbol('a', DeferredType())
    with pytest.raises(ValueError) as error:
        sym.constant_value = 1.0
    assert ("Error setting constant value for symbol 'a'. A DataSymbol with "
            "a constant value must be a scalar or an array but found "
            "'DeferredType'." in str(error.value))

    # Test with invalid constant expressions
    ct_expr = Return()
    with pytest.raises(ValueError) as error:
        _ = DataSymbol('a', INTEGER_SINGLE_TYPE, constant_value=ct_expr)
    assert "Error setting constant value for symbol 'a'. PSyIR static " \
        "expressions can only contain PSyIR literal, operation or reference" \
        " nodes but found:" in str(error.value)

    with pytest.raises(ValueError) as error:
        DataSymbol('a',
                   INTEGER_SINGLE_TYPE,
                   interface=ArgumentInterface(),
                   constant_value=9)
    assert ("Error setting constant value for symbol 'a'. A DataSymbol with "
            "an ArgumentInterface can not have a constant value."
            in str(error.value))

    with pytest.raises(ValueError) as error:
        DataSymbol('a', INTEGER_SINGLE_TYPE, constant_value=9.81)
    assert ("Error setting constant value for symbol 'a'. This DataSymbol "
            "instance datatype is 'Scalar<INTEGER, SINGLE>' which "
            "means the constant value is expected to be") in str(error.value)
    assert "'int'>' but found " in str(error.value)
    assert "'float'>'." in str(error.value)

    with pytest.raises(ValueError) as error:
        DataSymbol('a', CHARACTER_TYPE, constant_value=42)
    assert ("Error setting constant value for symbol 'a'. This DataSymbol "
            "instance datatype is 'Scalar<CHARACTER, UNDEFINED>' which "
            "means the constant value is expected to be") in str(error.value)
    assert "'str'>' but found " in str(error.value)
    assert "'int'>'." in str(error.value)

    with pytest.raises(ValueError) as error:
        DataSymbol('a', BOOLEAN_TYPE, constant_value="hello")
    assert ("Error setting constant value for symbol 'a'. This DataSymbol "
            "instance datatype is 'Scalar<BOOLEAN, UNDEFINED>' which "
            "means the constant value is expected to be") in str(error.value)
    assert "'bool'>' but found " in str(error.value)
    assert "'str'>'." in str(error.value)
Beispiel #14
0
def test_children_is_orphan_validation():
    ''' Test that all kinds of children addition operations make sure that a
    child is orphan before accepting it as its own child. '''
    # Create 2 schedules and add a child in the first Schedule
    schedule1 = Schedule()
    schedule2 = Schedule()
    statement = Return(parent=schedule1)
    schedule1.addchild(statement)

    # Try to move the child without removing the parent connection first
    errmsg = ("Item 'Return' can't be added as child of 'Schedule' because "
              "it is not an orphan. It already has a 'Schedule' as a parent.")
    with pytest.raises(GenerationError) as error:
        schedule2.addchild(statement)
    assert errmsg in str(error.value)

    with pytest.raises(GenerationError) as error:
        schedule2.children.append(statement)
    assert errmsg in str(error.value)

    with pytest.raises(GenerationError) as error:
        schedule2.children.insert(0, statement)
    assert errmsg in str(error.value)

    with pytest.raises(GenerationError) as error:
        schedule2.children.extend([statement])
    assert errmsg in str(error.value)

    with pytest.raises(GenerationError) as error:
        schedule2.children = [statement]
    assert errmsg in str(error.value)

    schedule2.addchild(Return())
    with pytest.raises(GenerationError) as error:
        schedule2.children[0] = statement
    assert errmsg in str(error.value)

    # It can be added when it has been detached from its previous parent
    schedule2.addchild(statement.detach())
Beispiel #15
0
def test_children_is_orphan_same_parent():
    ''' Test children addition operations with a node that is not an orphan
    and already belongs to the parent to which it is being added.'''
    # Create 2 schedules and add a child in the first Schedule
    schedule1 = Schedule()
    statement = Return(parent=schedule1)
    schedule1.addchild(statement)

    with pytest.raises(GenerationError) as error:
        schedule1.addchild(statement)
    assert ("Item 'Return' can't be added as child of 'Schedule' because "
            "it is not an orphan. It already has a 'Schedule' as a parent."
            in str(error.value))
Beispiel #16
0
def test_psyirvisitor_visit_return_node():
    '''Check that when a return PSyIR node is found the actual method
    called is 'return_node'. This is done to avoid clashing with the
    Python keyword.

    '''
    return_node = Return()
    test_visitor = PSyIRVisitor()
    with pytest.raises(VisitorError) as excinfo:
        _ = test_visitor(return_node)
    assert ("Visitor Error: Unsupported node 'Return' found: method names "
            "attempted were ['return_node', 'statement_node', 'node_node']."
            in str(excinfo.value))
Beispiel #17
0
def test_fusetrans_error_incomplete():
    ''' Check that we reject attempts to fuse loops which are incomplete. '''
    from psyclone.psyir.nodes import Return
    from psyclone.transformations import LoopFuseTrans
    sch = Schedule()
    loop1 = Loop(variable=DataSymbol("i", INTEGER_TYPE), parent=sch)
    loop2 = Loop(variable=DataSymbol("j", INTEGER_TYPE), parent=sch)
    sch.addchild(loop1)
    sch.addchild(loop2)

    fuse = LoopFuseTrans()

    # Check first loop
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert ("Error in LoopFuseTrans transformation. The target loop must have "
            "four children but found: []" in str(err.value))

    loop1.addchild(Literal("start", INTEGER_TYPE, parent=loop1))
    loop1.addchild(Literal("stop", INTEGER_TYPE, parent=loop1))
    loop1.addchild(Literal("step", INTEGER_TYPE, parent=loop1))
    loop1.addchild(Schedule(parent=loop1))
    loop1.loop_body.addchild(Return(parent=loop1.loop_body))

    # Check second loop
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert ("Error in LoopFuseTrans transformation. The target loop must have "
            "four children but found: []" in str(err.value))

    loop2.addchild(Literal("start", INTEGER_TYPE, parent=loop2))
    loop2.addchild(Literal("stop", INTEGER_TYPE, parent=loop2))
    loop2.addchild(Literal("step", INTEGER_TYPE, parent=loop2))
    loop2.addchild(Schedule(parent=loop2))
    loop2.loop_body.addchild(Return(parent=loop2.loop_body))

    # Validation should now pass
    fuse.validate(loop1, loop2)
Beispiel #18
0
def test_ifblock_properties():
    '''Test that an IfBlock node properties can be retrieved'''
    ifblock = IfBlock()

    # Condition can't be retrieved before it is added as a child.
    with pytest.raises(InternalError) as err:
        _ = ifblock.condition
    assert("IfBlock malformed or incomplete. It should have "
           "at least 2 children, but found 0." in str(err.value))

    ref1 = Reference(DataSymbol('condition1', BOOLEAN_TYPE),
                     parent=ifblock)
    ifblock.addchild(ref1)

    # If_body can't be retrieved before is added as a child.
    with pytest.raises(InternalError) as err:
        _ = ifblock.if_body
    assert("IfBlock malformed or incomplete. It should have "
           "at least 2 children, but found 1." in str(err.value))

    sch = Schedule()
    ifblock.addchild(sch)
    ret = Return()
    sch.addchild(ret)

    # Now we can retrieve the condition and the if_body, but else is empty
    assert ifblock.condition is ref1
    assert ifblock.if_body[0] is ret
    assert not ifblock.else_body

    sch2 = Schedule()
    ifblock.addchild(sch2)
    ret2 = Return()
    sch2.addchild(ret2)

    # Now we can retrieve else_body
    assert ifblock.else_body[0] is ret2
Beispiel #19
0
def test_ifblock_view_indices(capsys):
    ''' Check that the view method only displays indices on the nodes
    in the body (and else body) of an IfBlock. '''
    colouredif = colored("If", IfBlock._colour)
    colouredreturn = colored("Return", Return._colour)
    colouredref = colored("Reference", Reference._colour)
    condition = Reference(DataSymbol('condition1', REAL_SINGLE_TYPE))
    then_content = [Return()]
    ifblock = IfBlock.create(condition, then_content)
    ifblock.view()
    output, _ = capsys.readouterr()
    # Check that we only prepend child indices where it makes sense
    assert colouredif + "[]" in output
    assert "0: " + colouredreturn in output
    assert ": " + colouredref not in output
Beispiel #20
0
def test_container_children_validation():
    '''Test that children added to Container are validated. Container
    accepts just Container and kernelSchedule as children.

    '''
    container = Container.create("container", SymbolTable(), [])

    # Valid children
    container2 = Container.create("container2", SymbolTable(), [])
    container.addchild(container2)

    # Invalid children (e.g. Return Statement)
    ret = Return()
    with pytest.raises(GenerationError) as excinfo:
        container.addchild(ret)
    assert ("Item 'Return' can't be child 1 of 'Container'. The valid format"
            " is: '[Container | KernelSchedule | InvokeSchedule]*'."
            "" in str(excinfo.value))
Beispiel #21
0
def test_auto_invoke_return_last_stmt(parser):
    ''' Check that using the auto-invoke profiling option avoids including
    a return statement within the profiling region if it is the last statement
    in the routine. '''
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE)
    zero = Literal("0.0", REAL_TYPE)
    assign1 = Assignment.create(Reference(arg1), zero)
    kschedule = KernelSchedule.create("work", symbol_table,
                                      [assign1, Return()])
    # Double-check that the tree is as we expect
    assert isinstance(kschedule[-1], Return)

    Profiler.set_options([Profiler.INVOKES])
    Profiler.add_profile_nodes(kschedule, Loop)
    # The Return should be a sibling of the ProfileNode rather than a child
    assert isinstance(kschedule[0], ProfileNode)
    assert isinstance(kschedule[0].children[0].children[0], Assignment)
    assert isinstance(kschedule[1], Return)
Beispiel #22
0
def test_lower_named_profile_node():
    ''' Test that the lower_to_language_level method behaves as expected when
    a ProfileNode has pre-set names for the module and region.

    '''
    Profiler.set_options([Profiler.INVOKES])
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE)
    assign1 = Assignment.create(Reference(arg1), Literal("0.0", REAL_TYPE))
    kschedule = KernelSchedule.create("work1", symbol_table,
                                      [assign1, Return()])
    Profiler.add_profile_nodes(kschedule, Loop)
    pnode = kschedule.walk(ProfileNode)[0]
    # Manually set the module and region names (to save using a transformation)
    pnode._module_name = "my_mod"
    pnode._region_name = "first"
    kschedule.lower_to_language_level()
    cblocks = kschedule.walk(CodeBlock)
    assert ("PreStart('my_mod', 'first', 0, 0)"
            in str(cblocks[0].get_ast_nodes[0]))
Beispiel #23
0
def test_naryoperation_children_validation():
    '''Test that children added to NaryOperation are validated. NaryOperations
    accepts DataNodes nodes as children.

    '''
    nary = NaryOperation(NaryOperation.Operator.MAX)
    literal1 = Literal("1", INTEGER_SINGLE_TYPE)
    literal2 = Literal("2", INTEGER_SINGLE_TYPE)
    literal3 = Literal("3", INTEGER_SINGLE_TYPE)
    statement = Return()

    # DataNodes are valid
    nary.addchild(literal1)
    nary.addchild(literal2)
    nary.addchild(literal3)

    # Statements are not valid
    with pytest.raises(GenerationError) as excinfo:
        nary.addchild(statement)
    assert ("Item 'Return' can't be child 3 of 'NaryOperation'. The valid "
            "format is: '[DataNode]+'.") in str(excinfo.value)
Beispiel #24
0
def test_unaryoperation_children_validation():
    '''Test that children added to unaryOperation are validated.
    UnaryOperations accept just 1 DataNode as child.

    '''
    operation = UnaryOperation(UnaryOperation.Operator.SIN)
    literal1 = Literal("1", INTEGER_SINGLE_TYPE)
    literal2 = Literal("2", INTEGER_SINGLE_TYPE)
    statement = Return()

    # Statements are not valid
    with pytest.raises(GenerationError) as excinfo:
        operation.addchild(statement)
    assert ("Item 'Return' can't be child 0 of 'UnaryOperation'. The valid "
            "format is: 'DataNode'.") in str(excinfo.value)

    # First DataNodes is valid, but not subsequent ones
    operation.addchild(literal1)
    with pytest.raises(GenerationError) as excinfo:
        operation.addchild(literal2)
    assert ("Item 'Literal' can't be child 1 of 'UnaryOperation'. The valid "
            "format is: 'DataNode'.") in str(excinfo.value)
Beispiel #25
0
def test_psy_data_node_children_validation():
    '''Test that children added to PSyDataNode are validated. PSyDataNode
    accepts just one Schedule as its child.

    '''
    psy_node = PSyDataNode.create([], SymbolTable())
    del psy_node.children[0]

    # Invalid children (e.g. Return Statement)
    ret = Return()
    with pytest.raises(GenerationError) as excinfo:
        psy_node.addchild(ret)
    assert ("Item 'Return' can't be child 0 of 'PSyData'. The valid format"
            " is: 'Schedule'." in str(excinfo.value))

    # Valid children
    psy_node.addchild(Schedule())

    # Additional children
    with pytest.raises(GenerationError) as excinfo:
        psy_node.addchild(Schedule())
    assert ("Item 'Schedule' can't be child 1 of 'PSyData'. The valid format"
            " is: 'Schedule'." in str(excinfo.value))
Beispiel #26
0
def test_oclw_kernelschedule():
    '''Check the OpenCLWriter class kernelschedule_node visitor produces
    the expected OpenCL code.

    '''

    # The kernelschedule OpenCL Backend relies on abstract 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.value)

    # 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 = ArgumentInterface(ArgumentInterface.Access.UNKNOWN)
    i = DataSymbol('i', INTEGER_TYPE, interface=interface)
    j = DataSymbol('j', INTEGER_TYPE, interface=interface)
    array_type = ArrayType(REAL_TYPE, [10, 10])
    data1 = DataSymbol('data1', array_type, interface=interface)
    data2 = DataSymbol('data2', array_type, 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)
    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\n"

    # Set a local_size value different to 1 into the KernelSchedule
    oclwriter = OpenCLWriter(kernels_local_size=4)
    result = oclwriter(kschedule)

    assert result == "" \
        "__attribute__((reqd_work_group_size(4, 1, 1)))\n" \
        "__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\n"

    # Add a symbol with a deferred interface and check that this raises the
    # expected error
    array_type = ArrayType(REAL_TYPE, [10, 10])
    kschedule.symbol_table.add(
        DataSymbol('broken', array_type, interface=UnresolvedInterface()))
    with pytest.raises(VisitorError) as err:
        _ = oclwriter(kschedule)
    assert ("symbol table contains unresolved data entries (i.e. that have no "
            "defined Interface) which are not used purely to define the "
            "precision of other symbols: 'broken'" in str(err.value))
Beispiel #27
0
def test_children_validation():
    ''' Test that nodes are validated when inserted as children of other
    nodes. For simplicity we use Node subclasses to test this functionality
    across a range of possible operations.

    The specific logic of each validate method will be tested individually
    inside each Node test file.
    '''
    assignment = Assignment()
    return_stmt = Return()
    reference = Reference(DataSymbol("a", INTEGER_TYPE))

    assert isinstance(assignment.children, (ChildrenList, list))

    # Try adding a invalid child (e.g. a return_stmt into an assingment)
    with pytest.raises(GenerationError) as error:
        assignment.addchild(return_stmt)
    assert "Item 'Return' can't be child 0 of 'Assignment'. The valid format" \
        " is: 'DataNode, DataNode'." in str(error.value)

    # The same behaviour occurs when list insertion operations are used.
    with pytest.raises(GenerationError):
        assignment.children.append(return_stmt)

    with pytest.raises(GenerationError):
        assignment.children[0] = return_stmt

    with pytest.raises(GenerationError):
        assignment.children.insert(0, return_stmt)

    with pytest.raises(GenerationError):
        assignment.children.extend([return_stmt])

    with pytest.raises(GenerationError):
        assignment.children = assignment.children + [return_stmt]

    # Valid nodes are accepted
    assignment.addchild(reference)

    # Check displaced items are also be checked when needed
    start = Literal("0", INTEGER_TYPE)
    stop = Literal("1", INTEGER_TYPE)
    step = Literal("2", INTEGER_TYPE)
    child_node = Assignment.create(Reference(DataSymbol("tmp", REAL_TYPE)),
                                   Reference(DataSymbol("i", REAL_TYPE)))
    loop_variable = DataSymbol("idx", INTEGER_TYPE)
    loop = Loop.create(loop_variable, start, stop, step, [child_node])
    with pytest.raises(GenerationError):
        loop.children.insert(1, Literal("0", INTEGER_TYPE))

    with pytest.raises(GenerationError):
        loop.children.remove(stop)

    with pytest.raises(GenerationError):
        del loop.children[2]

    with pytest.raises(GenerationError):
        loop.children.pop(2)

    with pytest.raises(GenerationError):
        loop.children.reverse()

    # But the in the right circumstances they work fine
    assert isinstance(loop.children.pop(), Schedule)
    loop.children.reverse()
    assert loop.children[0].value == "2"
Beispiel #28
0
def test_return_node_str():
    ''' Check the node_str method of the Return class.'''
    from psyclone.psyir.nodes.node import colored, SCHEDULE_COLOUR_MAP
    return_stmt = Return()
    coloredtext = colored("Return", SCHEDULE_COLOUR_MAP["Return"])
    assert coloredtext+"[]" in return_stmt.node_str()
Beispiel #29
0
def test_return_node_str():
    ''' Check the node_str method of the Return class.'''
    return_stmt = Return()
    coloredtext = colored("Return", Return._colour)
    assert coloredtext + "[]" in return_stmt.node_str()
Beispiel #30
0
def test_return_can_be_printed():
    '''Test that a Return instance can always be printed (i.e. is
    initialised fully)'''
    return_stmt = Return()
    assert "Return[]" in str(return_stmt)