Пример #1
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)
Пример #2
0
def test_assignment_children_validation():
    '''Test that children added to assignment are validated. Assignment
    accepts just 2 children and both are DataNodes.

    '''
    # Create method with lhs not a Node.
    with pytest.raises(GenerationError) as excinfo:
        _ = Assignment.create("invalid", Literal("0.0", REAL_SINGLE_TYPE))
    assert ("Item 'str' can't be child 0 of 'Assignment'. The valid format "
            "is: 'DataNode, DataNode'.") in str(excinfo.value)

    # Create method with rhs not a Node.
    with pytest.raises(GenerationError) as excinfo:
        _ = Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
                              "invalid")
    assert ("Item 'str' can't be child 1 of 'Assignment'. The valid format "
            "is: 'DataNode, DataNode'.") in str(excinfo.value)

    # Direct assignment of a 3rd children
    assignment = Assignment.create(
        Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
        Literal("0.0", REAL_SINGLE_TYPE))
    with pytest.raises(GenerationError) as excinfo:
        assignment.children.append(Literal("0.0", REAL_SINGLE_TYPE))
    assert ("Item 'Literal' can't be child 2 of 'Assignment'. The valid format"
            " is: 'DataNode, DataNode'.") in str(excinfo.value)
Пример #3
0
def test_is_array_range():
    '''test that the is_array_range method behaves as expected, returning
    true if the LHS of the assignment is an array range access and
    false otherwise.

    '''
    one = Literal("1.0", REAL_TYPE)
    int_one = Literal("1", INTEGER_TYPE)
    var = DataSymbol("x", REAL_TYPE)
    reference = Reference(var)

    # lhs is not an array
    assignment = Assignment.create(reference, one)
    assert not assignment.is_array_range

    # lhs is an array reference but has no range
    array_type = ArrayType(REAL_TYPE, [10, 10])
    symbol = DataSymbol("x", array_type)
    array_ref = ArrayReference(symbol, [1, 3])
    assignment = Assignment.create(array_ref, one)
    assert not assignment.is_array_range

    # lhs is an array reference with a range
    my_range = Range.create(int_one, int_one, int_one)
    array_ref = ArrayReference.create(symbol, [my_range, int_one])
    assignment = Assignment.create(array_ref, one)
    assert assignment.is_array_range
Пример #4
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)
Пример #5
0
def test_is_not_array_range():
    ''' Test that is_array_range correctly rejects things that aren't
    an assignment to an array range.

    '''
    int_one = Literal("1", INTEGER_SINGLE_TYPE)
    one = Literal("1.0", REAL_TYPE)
    var = DataSymbol("x", REAL_TYPE)
    reference = Reference(var)

    # lhs is not an array
    assignment = Assignment.create(reference, one)
    assert assignment.is_array_range is False

    # lhs is an array reference but has no range
    array_type = ArrayType(REAL_TYPE, [10, 10])
    symbol = DataSymbol("y", array_type)
    array_ref = Reference(symbol)
    assignment = Assignment.create(array_ref, one.copy())
    assert assignment.is_array_range is False

    # lhs is an array reference but the single index value is obtained
    # using an array range, y(1, SUM(map(:), 1)) = 1.0
    int_array_type = ArrayType(INTEGER_SINGLE_TYPE, [10])
    map_sym = DataSymbol("map", int_array_type)
    start = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                   Reference(map_sym), int_one.copy())
    stop = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                  Reference(map_sym), int_one.copy())
    my_range = Range.create(start, stop)
    sum_op = BinaryOperation.create(BinaryOperation.Operator.SUM,
                                    ArrayReference.create(map_sym, [my_range]),
                                    int_one.copy())
    assignment = Assignment.create(
        ArrayReference.create(symbol, [int_one.copy(), sum_op]), one.copy())
    assert assignment.is_array_range is False

    # When the slice has two operator ancestors, one of which is a reduction
    # e.g y(1, SUM(ABS(map(:)), 1)) = 1.0
    abs_op = UnaryOperation.create(
        UnaryOperation.Operator.ABS,
        ArrayReference.create(map_sym, [my_range.copy()]))
    sum_op2 = BinaryOperation.create(BinaryOperation.Operator.SUM, abs_op,
                                     int_one.copy())
    assignment = Assignment.create(
        ArrayReference.create(symbol, [int_one.copy(), sum_op2]), one.copy())
    assert assignment.is_array_range is False

    # lhs is a scalar member of a structure
    grid_type = StructureType.create([
        ("dx", REAL_SINGLE_TYPE, Symbol.Visibility.PUBLIC),
        ("dy", REAL_SINGLE_TYPE, Symbol.Visibility.PUBLIC)
    ])
    grid_type_symbol = DataTypeSymbol("grid_type", grid_type)
    grid_sym = DataSymbol("grid", grid_type_symbol)
    assignment = Assignment.create(StructureReference.create(grid_sym, ["dx"]),
                                   one.copy())
    assert assignment.is_array_range is False
Пример #6
0
def test_ifblock_create_invalid():
    '''Test that the create method in an IfBlock class raises the expected
    exception if the provided input is invalid.

    '''
    if_condition = Literal('true', BOOLEAN_TYPE)
    if_body = [
        Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
                          Literal("0.0", REAL_SINGLE_TYPE)),
        Assignment.create(Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                          Literal("1.0", REAL_SINGLE_TYPE))
    ]

    # if_condition not a Node.
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create("True", if_body)
    assert ("Item 'str' can't be child 0 of 'If'. The valid format is: "
            "'DataNode, Schedule [, Schedule]'.") in str(excinfo.value)

    # One or more if body not a Node.
    if_body_err = [
        Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
                          Literal("0.0", REAL_SINGLE_TYPE)), "invalid"
    ]
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, if_body_err)
    assert ("Item 'str' can't be child 1 of 'Schedule'. The valid format is: "
            "'[Statement]*'.") in str(excinfo.value)

    # If body not a list.
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, "invalid")
    assert ("if_body argument in create method of IfBlock class should be a "
            "list.") in str(excinfo.value)

    # One of more of else_body not a Node.
    else_body_err = [
        Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
                          Literal("1.0", REAL_SINGLE_TYPE)), "invalid"
    ]
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, if_body, else_body_err)
    assert ("Item 'str' can't be child 1 of 'Schedule'. The valid format is: "
            "'[Statement]*'.") in str(excinfo.value)

    # Else body not a list.
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, if_body, "invalid")
    assert ("else_body argument in create method of IfBlock class should be a "
            "list.") in str(excinfo.value)
Пример #7
0
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))
Пример #8
0
def test_validate():
    '''Check that the validate method raises exceptions as expected.'''

    dummy = DummyTrans()
    # operator_name, classes and operators are usually set by the
    # Transformation's __init__ method but set them manually here to
    # avoid creating multiple implementations of DummyTrans.
    dummy._operator_name = "hello"
    dummy._classes = (UnaryOperation, )
    dummy._operators = (UnaryOperation.Operator.ABS, )

    var = Literal("0.0", REAL_TYPE)
    operator = UnaryOperation.create(UnaryOperation.Operator.ABS, var)

    with pytest.raises(TransformationError) as excinfo:
        dummy.validate(operator)
    assert ("This transformation requires the operator to be part of an "
            "assignment statement, but no such assignment was found."
            in str(excinfo.value))

    reference = Reference(DataSymbol("fred", REAL_TYPE))
    _ = Assignment.create(lhs=reference, rhs=operator)

    with pytest.raises(TransformationError) as excinfo:
        dummy.validate(None)
    assert ("The supplied node argument is not a hello operator, found "
            "'NoneType'." in str(excinfo.value))

    with pytest.raises(TransformationError) as excinfo:
        dummy.validate(UnaryOperation(UnaryOperation.Operator.SIN, var))
    assert ("Error in Hello2CodeTrans transformation. The supplied node "
            "operator is invalid, found 'Operator.SIN'." in str(excinfo.value))

    dummy.validate(operator)
def test_find_or_create_change_symbol_type():
    ''' Check that the _find_or_create_imported_symbol routine correctly
    updates the class of the located symbol if it is not an instance of
    the requested symbol type.
    '''
    # pylint: disable=unidiomatic-typecheck
    # Create some suitable PSyIR from scratch
    symbol_table = SymbolTable()
    tmp_sym = symbol_table.new_symbol("tmp")
    sub_sym = symbol_table.new_symbol("my_sub")
    kernel1 = KernelSchedule.create("mod_1", SymbolTable(), [])
    _ = Container.create("container_name", symbol_table, [kernel1])
    assign = Assignment.create(Reference(tmp_sym), Literal("1.0", REAL_TYPE))
    kernel1.addchild(assign)
    # Search for the 'tmp' symbol
    sym = _find_or_create_imported_symbol(assign, "tmp")
    assert sym is tmp_sym
    assert type(sym) == Symbol
    # Repeat but this time specify that we're expecting a DataSymbol
    sym = _find_or_create_imported_symbol(assign,
                                          "tmp",
                                          symbol_type=DataSymbol,
                                          datatype=REAL_TYPE)
    assert sym is tmp_sym
    assert type(sym) == DataSymbol
    assert sym.datatype == REAL_TYPE
    # Search for 'my_sub' and specify that it should be a RoutineSymbol
    sym2 = _find_or_create_imported_symbol(assign,
                                           "my_sub",
                                           symbol_type=RoutineSymbol)
    assert sym2 is sub_sym
    assert type(sym2) == RoutineSymbol
def test_find_or_create_imported_symbol_2():
    ''' Check that the _find_or_create_imported_symbol() method creates new
    symbols when appropriate. '''
    # Create some suitable PSyIR from scratch
    symbol_table = SymbolTable()
    symbol_table.add(DataSymbol("tmp", REAL_TYPE))
    kernel1 = KernelSchedule.create("mod_1", SymbolTable(), [])
    container = Container.create("container_name", symbol_table, [kernel1])
    xvar = DataSymbol("x", REAL_TYPE)
    xref = Reference(xvar)
    assign = Assignment.create(xref, Literal("1.0", REAL_TYPE))
    kernel1.addchild(assign)
    # We have no wildcard imports so there can be no symbol named 'undefined'
    with pytest.raises(SymbolError) as err:
        _ = _find_or_create_imported_symbol(assign, "undefined")
    assert "No Symbol found for name 'undefined'" in str(err.value)
    # We should be able to find the 'tmp' symbol in the parent Container
    sym = _find_or_create_imported_symbol(assign, "tmp")
    assert sym.datatype.intrinsic == ScalarType.Intrinsic.REAL
    # Add a wildcard import to the SymbolTable of the KernelSchedule
    new_container = ContainerSymbol("some_mod")
    new_container.wildcard_import = True
    kernel1.symbol_table.add(new_container)
    # Symbol not in any container but we do have wildcard imports so we
    # get a new symbol back
    new_symbol = _find_or_create_imported_symbol(assign, "undefined")
    assert new_symbol.name == "undefined"
    assert isinstance(new_symbol.interface, UnresolvedInterface)
    # pylint: disable=unidiomatic-typecheck
    assert type(new_symbol) == Symbol
    assert "undefined" not in container.symbol_table
    assert kernel1.symbol_table.lookup("undefined") is new_symbol
Пример #11
0
def test_scope():
    '''Test that the scope method in a Node instance returns the closest
    ancestor Schedule or Container Node (including itself) or raises
    an exception if one does not exist.

    '''
    kernel_symbol_table = SymbolTable()
    symbol = DataSymbol("tmp", REAL_TYPE)
    kernel_symbol_table.add(symbol)
    ref = Reference(symbol)
    assign = Assignment.create(ref, Literal("0.0", REAL_TYPE))
    kernel_schedule = KernelSchedule.create("my_kernel", kernel_symbol_table,
                                            [assign])
    container = Container.create("my_container", SymbolTable(),
                                 [kernel_schedule])
    assert ref.scope is kernel_schedule
    assert assign.scope is kernel_schedule
    assert kernel_schedule.scope is kernel_schedule
    assert container.scope is container

    anode = Literal("x", INTEGER_TYPE)
    with pytest.raises(SymbolError) as excinfo:
        _ = anode.scope
    assert ("Unable to find the scope of node "
            "'Literal[value:'x', Scalar<INTEGER, UNDEFINED>]' as "
            "none of its ancestors are Container or Schedule nodes."
            in str(excinfo.value))
Пример #12
0
def example_psyir(create_expression):
    '''Utility function that creates a PSyIR tree containing an ABS
    intrinsic operator and returns the operator.

    :param function create_expresssion: function used to create the \
        content of the ABS operator.

    :returns: PSyIR ABS operator instance.
    :rtype: :py:class:`psyclone.psyGen.UnaryOperation`

    '''
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol("arg",
                                   symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    local = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE)
    symbol_table.specify_argument_list([arg1])
    var1 = Reference(arg1)
    var2 = Reference(local)
    oper = UnaryOperation.Operator.ABS
    operation = UnaryOperation.create(oper, create_expression(var1))
    assign = Assignment.create(var2, operation)
    _ = KernelSchedule.create("abs_example", symbol_table, [assign])
    return operation
Пример #13
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)
Пример #14
0
def test_validate_intrinsic():
    '''Check that the validate method returns an exception if the rhs of
    the assignment contains an operator that only returns an array
    i.e. can't be performed elementwise. At the moment MATMUL is the
    only operator of this type.

    '''
    symbol_table = SymbolTable()
    array_x = create_array_x(symbol_table)
    array_y_2 = create_array_y_2d_slice(symbol_table)
    matmul = BinaryOperation.create(BinaryOperation.Operator.MATMUL, array_y_2,
                                    array_x)
    reference = ArrayReference.create(
        symbol_table.lookup("x"), [create_range(symbol_table.lookup("x"), 1)])
    assignment = Assignment.create(reference, matmul)

    trans = ArrayRange2LoopTrans()
    with pytest.raises(TransformationError) as info:
        trans.validate(assignment)
    assert ("Error in ArrayRange2LoopTrans transformation. The rhs of the "
            "supplied Assignment node 'BinaryOperation[operator:'MATMUL']\n"
            "ArrayReference[name:'y2']\nRange[]\nRange[]\n\n"
            "ArrayReference[name:'x']\nRange[]\n' contains the "
            "MATMUL operator which can't be performed elementwise."
            in str(info.value))
Пример #15
0
def test_create_errors():
    '''Test that the expected exceptions are raised when the arguments to
    the create method are invalid.

    '''
    variable = DataSymbol("ji", INTEGER_TYPE)
    start = Literal("2", INTEGER_TYPE)
    stop = Literal("10", INTEGER_TYPE)
    step = Literal("1", INTEGER_TYPE)
    x_var = DataSymbol("X", REAL_TYPE)
    children = Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))
    with pytest.raises(GenerationError) as info:
        _ = NemoLoop.create(None, start, stop, step, [children.copy()])
    assert ("Generation Error: variable property in Loop class should be a "
            "DataSymbol but found 'NoneType'" in str(info.value))
    with pytest.raises(GenerationError) as info:
        _ = NemoLoop.create(variable, None, stop, step, [children.copy()])
    assert ("Generation Error: Item 'NoneType' can't be child 0 of 'Loop'. "
            "The valid format is: 'DataNode, DataNode, DataNode, Schedule'."
            in str(info.value))
    with pytest.raises(GenerationError) as info:
        _ = NemoLoop.create(variable, start, None, step, [children.copy()])
    assert ("Generation Error: Item 'NoneType' can't be child 1 of 'Loop'. "
            "The valid format is: 'DataNode, DataNode, DataNode, Schedule'."
            in str(info.value))
    with pytest.raises(GenerationError) as info:
        _ = NemoLoop.create(variable, start, stop, None, [children.copy()])
    assert ("Generation Error: Item 'NoneType' can't be child 2 of 'Loop'. "
            "The valid format is: 'DataNode, DataNode, DataNode, Schedule'."
            in str(info.value))
    with pytest.raises(GenerationError) as info:
        _ = NemoLoop.create(variable, start, stop, step, None)
    assert ("Generation Error: children argument in create method of NemoLoop "
            "class should be a list but found 'NoneType'." in str(info.value))
Пример #16
0
def example_psyir_binary(create_expression):
    '''Utility function that creates a PSyIR tree containing a binary MIN
    intrinsic operator and returns the operator.

    :param function create_expresssion: function used to create the \
        content of the first argument of the MIN operator.

    :returns: PSyIR MIN operator instance.
    :rtype: :py:class:`psyclone.psyGen.BinaryOperation`

    '''
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol("arg",
                                   symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    arg2 = symbol_table.new_symbol("arg",
                                   symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    arg3 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE)
    symbol_table.specify_argument_list([arg1, arg2])
    var1 = Reference(arg1)
    var2 = Reference(arg2)
    var3 = Reference(arg3)
    oper = BinaryOperation.Operator.MIN
    operation = BinaryOperation.create(oper, create_expression(var1), var2)
    assign = Assignment.create(var3, operation)
    _ = KernelSchedule.create("min_example", symbol_table, [assign])
    return operation
Пример #17
0
def test_scoping_node_copy():
    ''' Test that the ScopingNode copy() method creates a new symbol table
    with copied symbols and updates the children references.'''

    # Since ScopingNode is abstract we will try this with a Schedule
    schedule = Schedule()
    symbol_a = schedule.symbol_table.new_symbol("a")
    symbol_b = schedule.symbol_table.new_symbol("b")

    schedule.addchild(
        Assignment.create(Reference(symbol_a), Reference(symbol_b)))

    new_schedule = schedule.copy()

    # Check that node generic copy() and _refine_copy() have been called
    # (e.g. children are not shallow copies and tree has been copied down
    # recursively)
    assert len(new_schedule.children) == 1
    assert new_schedule[0] is not schedule[0]
    assert new_schedule[0].lhs is not schedule[0].lhs
    assert new_schedule[0].rhs is not schedule[0].rhs

    # Check that the symbol_table has been deep copied
    assert new_schedule.symbol_table is not schedule.symbol_table
    assert new_schedule.symbol_table.lookup("a") is not \
        schedule.symbol_table.lookup("a")
    assert new_schedule.symbol_table.lookup("b") is not \
        schedule.symbol_table.lookup("b")

    # Check that the children references of the copied schedule point to
    # symbols in the new schedule's symbol table
    assert new_schedule[0].lhs.symbol not in schedule.symbol_table.symbols
    assert new_schedule[0].lhs.symbol in new_schedule.symbol_table.symbols
    assert new_schedule[0].rhs.symbol not in schedule.symbol_table.symbols
    assert new_schedule[0].rhs.symbol in new_schedule.symbol_table.symbols
Пример #18
0
def example_psyir_nary():
    '''Utility function that creates a PSyIR tree containing a nary MIN
    intrinsic operator and returns the operator.

    :returns: PSyIR MIN operator instance.
    :rtype: :py:class:`psyclone.psyGen.NaryOperation`

    '''
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol("arg",
                                   symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    arg2 = symbol_table.new_symbol("arg",
                                   symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    arg3 = symbol_table.new_symbol("arg",
                                   symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    arg4 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE)
    symbol_table.specify_argument_list([arg1, arg2, arg3])
    var1 = Reference(arg1)
    var2 = Reference(arg2)
    var3 = Reference(arg3)
    var4 = Reference(arg4)
    oper = NaryOperation.Operator.MIN
    operation = NaryOperation.create(oper, [var1, var2, var3])
    assign = Assignment.create(var4, operation)
    _ = KernelSchedule.create("min_example", symbol_table, [assign])
    return operation
Пример #19
0
def test_routine_create_invalid():
    '''Test that the create method in the Routine class raises the
    expected exceptions if the provided input is invalid.

    '''
    symbol_table = SymbolTable()
    symbol = DataSymbol("x", REAL_TYPE)
    symbol_table.add(symbol)
    children = [Assignment.create(Reference(symbol),
                                  Literal("1", REAL_TYPE))]

    # name is not a string.
    with pytest.raises(TypeError) as excinfo:
        _ = Routine.create(1, symbol_table, children)
    assert ("name argument in create method of Routine class "
            "should be a string but found 'int'.") in str(excinfo.value)

    # symbol_table not a SymbolTable.
    with pytest.raises(TypeError) as excinfo:
        _ = Routine.create("mod_name", "invalid", children)
    assert ("symbol_table argument in create method of Routine class "
            "should be a SymbolTable but found 'str'.") in str(excinfo.value)

    # children not a list.
    with pytest.raises(TypeError) as excinfo:
        _ = Routine.create("mod_name", symbol_table, "invalid")
    assert ("children argument in create method of Routine class "
            "should be a list but found 'str'." in str(excinfo.value))

    # contents of children list are not Node.
    with pytest.raises(TypeError) as excinfo:
        _ = Routine.create("mod_name", symbol_table, ["invalid"])
    assert (
        "child of children argument in create method of Routine class "
        "should be a PSyIR Node but found 'str'." in str(excinfo.value))
Пример #20
0
def test_cw_array():
    '''Check the CWriter class array method correctly prints
    out the C representation of an array.

    '''
    cwriter = CWriter()

    symbol = DataSymbol('a', REAL_TYPE)
    arr = ArrayReference(symbol)
    lit = Literal('0.0', REAL_TYPE)
    assignment = Assignment.create(arr, lit)

    # An array without any children (dimensions) should produce an error.
    with pytest.raises(VisitorError) as excinfo:
        result = cwriter(assignment)
    assert "Arrays must have at least 1 dimension but found node: '" \
        in str(excinfo.value)

    # Dimensions can be references, literals or operations
    arr.addchild(Reference(DataSymbol('b', INTEGER_TYPE), parent=arr))
    arr.addchild(Literal('1', INTEGER_TYPE, parent=arr))
    uop = UnaryOperation.create(UnaryOperation.Operator.MINUS,
                                Literal('2', INTEGER_TYPE))
    uop.parent = arr
    arr.addchild(uop)

    result = cwriter(assignment)
    # Results is reversed and flatten (row-major 1D)
    # dimensions are called <name>LEN<dimension> by convention
    assert result == "a[(-2) * aLEN2 * aLEN1 + 1 * aLEN1 + b] = 0.0;\n"
Пример #21
0
def test_array_range_with_reduction():
    ''' Test that we correctly identify an array range when it is the result
        of a reduction from an array, e.g x(1, INT(SUM(map(:, :), 1))) = 1.0

    '''
    one = Literal("1.0", REAL_TYPE)
    int_one = Literal("1", INTEGER_TYPE)
    int_two = Literal("2", INTEGER_TYPE)
    int_array_type = ArrayType(INTEGER_SINGLE_TYPE, [10, 10])
    map_sym = DataSymbol("map", int_array_type)
    array_type = ArrayType(REAL_TYPE, [10, 10])
    symbol = DataSymbol("x", array_type)
    lbound1 = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                     Reference(map_sym), int_one.copy())
    ubound1 = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                     Reference(map_sym), int_one.copy())
    my_range1 = Range.create(lbound1, ubound1)
    lbound2 = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                     Reference(map_sym), int_two.copy())
    ubound2 = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                     Reference(map_sym), int_two.copy())
    my_range2 = Range.create(lbound2, ubound2)
    bsum_op = BinaryOperation.create(
        BinaryOperation.Operator.SUM,
        ArrayReference.create(map_sym, [my_range1, my_range2]), int_one.copy())
    int_op2 = UnaryOperation.create(UnaryOperation.Operator.INT, bsum_op)
    assignment = Assignment.create(
        ArrayReference.create(symbol, [int_one.copy(), int_op2]), one.copy())
    assert assignment.is_array_range is True
Пример #22
0
def test_create():
    '''Test that the static create() method creates a NemoLoop instance
    and its children corectly.

    '''
    variable = DataSymbol("ji", INTEGER_TYPE)
    start = Literal("2", INTEGER_TYPE)
    stop = Literal("10", INTEGER_TYPE)
    step = Literal("1", INTEGER_TYPE)
    x_var = DataSymbol("X", REAL_TYPE)
    children = [Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))]
    nemo_loop = NemoLoop.create(variable, start, stop, step, children)
    assert isinstance(nemo_loop, NemoLoop)
    assert nemo_loop.loop_type == "lon"
    assert isinstance(nemo_loop.loop_body, Schedule)
    assert len(nemo_loop.loop_body.children) == 1
    assert nemo_loop.loop_body.children[0] is children[0]
    assert children[0].parent is nemo_loop.loop_body
    assert nemo_loop.loop_body.parent is nemo_loop
    assert nemo_loop.variable is variable
    assert nemo_loop.start_expr is start
    assert nemo_loop.stop_expr is stop
    assert nemo_loop.step_expr is step
    writer = FortranWriter()
    result = writer(nemo_loop)
    assert ("do ji = 2, 10, 1\n" "  X = 3.0\n" "enddo" in result)
Пример #23
0
def test_ifblock_create():
    '''Test that the create method in an IfBlock class correctly creates
    an IfBlock instance.

    '''
    # Without an else clause.
    if_condition = Literal('true', BOOLEAN_TYPE)
    if_body = [
        Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
                          Literal("0.0", REAL_SINGLE_TYPE)),
        Assignment.create(Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                          Literal("1.0", REAL_SINGLE_TYPE))
    ]
    ifblock = IfBlock.create(if_condition, if_body)
    if_schedule = ifblock.children[1]
    assert isinstance(if_schedule, Schedule)
    check_links(ifblock, [if_condition, if_schedule])
    check_links(if_schedule, if_body)
    result = FortranWriter().ifblock_node(ifblock)
    assert result == ("if (.true.) then\n"
                      "  tmp=0.0\n"
                      "  tmp2=1.0\n"
                      "end if\n")

    # With an else clause.
    else_body = [
        Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
                          Literal("1.0", REAL_SINGLE_TYPE)),
        Assignment.create(Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                          Literal("0.0", REAL_SINGLE_TYPE))
    ]
    ifblock = IfBlock.create(if_condition, if_body, else_body)
    if_schedule = ifblock.children[1]
    assert isinstance(if_schedule, Schedule)
    else_schedule = ifblock.children[2]
    assert isinstance(else_schedule, Schedule)
    check_links(ifblock, [if_condition, if_schedule, else_schedule])
    check_links(if_schedule, if_body)
    check_links(else_schedule, else_body)
    result = FortranWriter().ifblock_node(ifblock)
    assert result == ("if (.true.) then\n"
                      "  tmp=0.0\n"
                      "  tmp2=1.0\n"
                      "else\n"
                      "  tmp=1.0\n"
                      "  tmp2=0.0\n"
                      "end if\n")
Пример #24
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)
Пример #25
0
def test_assignment_create():
    '''Test that the create method in the Assignment class correctly
    creates an Assignment instance.

    '''
    lhs = Reference(DataSymbol("tmp", REAL_SINGLE_TYPE))
    rhs = Literal("0.0", REAL_SINGLE_TYPE)
    assignment = Assignment.create(lhs, rhs)
    check_links(assignment, [lhs, rhs])
    result = FortranWriter().assignment_node(assignment)
    assert result == "tmp = 0.0\n"
Пример #26
0
def test_cw_assignment():
    '''Check the CWriter class assignment method generate the appropriate
    output.

    '''
    assignment = Assignment.create(Reference(DataSymbol('a', REAL_TYPE)),
                                   Reference(DataSymbol('b', REAL_TYPE)))
    # Generate C from the PSyIR schedule
    cwriter = CWriter()
    result = cwriter(assignment)
    assert result == "a = b;\n"
Пример #27
0
def test_create_unknown():
    '''Test that the static create() method creates a NemoLoop instance
    with an unknown loop type if the loop type is not recognised.

    '''
    variable = DataSymbol("idx", INTEGER_TYPE)
    start = Literal("2", INTEGER_TYPE)
    stop = Literal("10", INTEGER_TYPE)
    step = Literal("1", INTEGER_TYPE)
    x_var = DataSymbol("X", REAL_TYPE)
    children = [Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))]
    nemo_loop = NemoLoop.create(variable, start, stop, step, children)
    assert nemo_loop.loop_type == "unknown"
Пример #28
0
def test_routine_create():
    '''Test that the create method correctly creates a Routine instance. '''
    symbol_table = SymbolTable()
    symbol = DataSymbol("tmp", REAL_TYPE)
    symbol_table.add(symbol)
    assignment = Assignment.create(Reference(symbol),
                                   Literal("0.0", REAL_TYPE))
    kschedule = Routine.create("mod_name", symbol_table, [assignment],
                               is_program=True, return_type=INTEGER_TYPE)
    assert isinstance(kschedule, Routine)
    check_links(kschedule, [assignment])
    assert kschedule.symbol_table is symbol_table
    assert kschedule.is_program
    assert kschedule.return_type == INTEGER_TYPE
Пример #29
0
def test_cw_size():
    ''' Check the CWriter class SIZE method raises the expected error since
    there is no C equivalent. '''
    cwriter = CWriter()
    arr = ArrayReference(DataSymbol('a', INTEGER_TYPE))
    lit = Literal('1', INTEGER_TYPE)
    size = BinaryOperation.create(BinaryOperation.Operator.SIZE, arr, lit)
    lhs = Reference(DataSymbol('length', INTEGER_TYPE))
    assignment = Assignment.create(lhs, size)

    with pytest.raises(VisitorError) as excinfo:
        cwriter(assignment)
    assert ("C backend does not support the 'Operator.SIZE' operator"
            in str(excinfo.value))
Пример #30
0
def test_kernel():
    '''Test that the kernel method behaves as expected.'''
    variable = DataSymbol("ji", INTEGER_TYPE)
    start = Literal("2", INTEGER_TYPE)
    stop = Literal("10", INTEGER_TYPE)
    step = Literal("1", INTEGER_TYPE)
    x_var = DataSymbol("X", REAL_TYPE)
    children = [Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))]
    nemo_loop = NemoLoop.create(variable, start, stop, step, children)
    assert not nemo_loop.kernel

    schedule = nemo_loop.loop_body
    nemo_kern = NemoKern(schedule.pop_all_children())
    schedule.children = [nemo_kern]
    assert nemo_loop.kernel

    children = [Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))]
    nemo_kern = NemoKern(children)
    schedule.children.append(nemo_kern)
    with pytest.raises(NotImplementedError) as info:
        _ = nemo_loop.kernel
    assert ("Kernel getter method does not yet support a loop containing more "
            "than one kernel but this loop contains 2" in str(info.value))