Пример #1
0
def create_expr(symbol_table):
    '''Utility routine that creates and returns an expression containing a
    number of array references containing range nodes. The expression
    looks like the following (using Fortran array notation):

    x(2:n:2)*z(1,2:n:2)+a(1)

    :param symbol_table: the symbol table to which we add the array \
        symbols.
    :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable`

    :returns: an expression containing 3 array references, 2 of which \
        contain ranges.
    :rtype: :py:class:`psyclone.psyir.nodes.BinaryOperation`

    '''
    array_symbol = DataSymbol("x", ArrayType(REAL_TYPE, [10]))
    symbol_table.add(array_symbol)
    symbol_n = symbol_table.lookup("n")
    array_x = ArrayReference.create(array_symbol,
                                    [create_stepped_range(symbol_n)])
    array_symbol = DataSymbol("z", ArrayType(REAL_TYPE, [10, 10]))
    symbol_table.add(array_symbol)
    array_z = ArrayReference.create(
        array_symbol,
        [Literal("1", INTEGER_TYPE),
         create_stepped_range(symbol_n)])
    array_symbol = DataSymbol("a", ArrayType(REAL_TYPE, [10]))
    array_a = ArrayReference.create(array_symbol, [Literal("1", INTEGER_TYPE)])
    symbol_table.add(array_symbol)
    mult = BinaryOperation.create(BinaryOperation.Operator.MUL, array_x,
                                  array_z)
    add = BinaryOperation.create(BinaryOperation.Operator.ADD, mult, array_a)
    return add
Пример #2
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
Пример #3
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
Пример #4
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
Пример #5
0
def test_array_node_str():
    ''' Check the node_str method of the ArrayReference class.'''
    kschedule = KernelSchedule("kname")
    array_type = ArrayType(INTEGER_SINGLE_TYPE, [ArrayType.Extent.ATTRIBUTE])
    symbol = DataSymbol("aname", array_type)
    kschedule.symbol_table.add(symbol)
    array = ArrayReference(symbol)
    coloredtext = colored("ArrayReference", ArrayReference._colour)
    assert coloredtext + "[name:'aname']" in array.node_str()
Пример #6
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"
Пример #7
0
def test_reference_accesses_bounds(operator_type):
    '''Test that the reference_accesses method behaves as expected when
    the reference is the first argument to either the lbound or ubound
    intrinsic as that is simply looking up the array bounds (therefore
    var_access_info should be empty) and when the reference is the
    second argument of either the lbound or ubound intrinsic (in which
    case the access should be a read).

    '''
    # Note, one would usually expect UBOUND to provide the upper bound
    # of a range but to simplify the test both LBOUND and UBOUND are
    # used for the lower bound. This does not affect the test.
    one = Literal("1", INTEGER_TYPE)
    array_symbol = DataSymbol("test", ArrayType(REAL_TYPE, [10]))
    array_ref1 = Reference(array_symbol)
    array_ref2 = Reference(array_symbol)
    array_access = ArrayReference.create(array_symbol, [one])

    # test when first or second argument to LBOUND or UBOUND is an
    # array reference
    operator = BinaryOperation.create(operator_type, array_ref1, array_ref2)
    array_access.children[0] = Range.create(operator, one, one)
    var_access_info = VariablesAccessInfo()
    array_ref1.reference_accesses(var_access_info)
    assert str(var_access_info) == ""
    var_access_info = VariablesAccessInfo()
    array_ref2.reference_accesses(var_access_info)
    assert str(var_access_info) == "test: READ"
Пример #8
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))
Пример #9
0
def test_array_create_invalid3():
    '''Test that the create method in an ArrayReference class raises the
    expected exception if the provided input is invalid.

    '''
    # symbol argument is not a DataSymbol
    with pytest.raises(GenerationError) as excinfo:
        _ = ArrayReference.create([], [])
    assert ("symbol argument in create method of ArrayReference class should "
            "be a DataSymbol but found 'list'." in str(excinfo.value))

    # children not a list
    with pytest.raises(GenerationError) as excinfo:
        _ = ArrayReference.create(DataSymbol("temp", REAL_SINGLE_TYPE),
                                  "invalid")
    assert ("indices argument in create method of ArrayReference class should"
            " be a list but found 'str'." in str(excinfo.value))
Пример #10
0
def create_matmul():
    '''Utility function that creates a valid matmul node for use with
    subsequent tests.

    '''
    symbol_table = SymbolTable()
    one = Literal("1", INTEGER_TYPE)
    two = Literal("2", INTEGER_TYPE)
    index = DataSymbol("idx", INTEGER_TYPE, constant_value=3)
    symbol_table.add(index)
    array_type = ArrayType(REAL_TYPE, [5, 10, 15])
    mat_symbol = DataSymbol("x", array_type)
    symbol_table.add(mat_symbol)
    lbound1 = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                     Reference(mat_symbol), one.copy())
    ubound1 = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                     Reference(mat_symbol), one.copy())
    my_mat_range1 = Range.create(lbound1, ubound1, one.copy())
    lbound2 = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                     Reference(mat_symbol), two.copy())
    ubound2 = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                     Reference(mat_symbol), two.copy())
    my_mat_range2 = Range.create(lbound2, ubound2, one.copy())
    matrix = ArrayReference.create(
        mat_symbol, [my_mat_range1, my_mat_range2,
                     Reference(index)])
    array_type = ArrayType(REAL_TYPE, [10, 20])
    vec_symbol = DataSymbol("y", array_type)
    symbol_table.add(vec_symbol)
    lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                    Reference(vec_symbol), one.copy())
    ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                    Reference(vec_symbol), one.copy())
    my_vec_range = Range.create(lbound, ubound, one.copy())
    vector = ArrayReference.create(
        vec_symbol, [my_vec_range, Reference(index)])
    matmul = BinaryOperation.create(BinaryOperation.Operator.MATMUL, matrix,
                                    vector)
    lhs_type = ArrayType(REAL_TYPE, [10])
    lhs_symbol = DataSymbol("result", lhs_type)
    symbol_table.add(lhs_symbol)
    lhs = Reference(lhs_symbol)
    assign = Assignment.create(lhs, matmul)
    KernelSchedule.create("my_kern", symbol_table, [assign])
    return matmul
Пример #11
0
def test_array_can_be_printed():
    '''Test that an ArrayReference instance can always be printed (i.e. is
    initialised fully)'''
    kschedule = KernelSchedule("kname")
    symbol = DataSymbol("aname", INTEGER_SINGLE_TYPE)
    kschedule.symbol_table.add(symbol)
    assignment = Assignment()
    array = ArrayReference(symbol, assignment)
    assert "ArrayReference[name:'aname']\n" in str(array)
Пример #12
0
def test_array_is_lower_bound():
    '''Test that the is_lower_bound method in the Array Node works as
    expected.

    '''
    one = Literal("1", INTEGER_TYPE)
    array = ArrayReference.create(DataSymbol("test",
                                             ArrayType(REAL_TYPE, [10])),
                                  [one])
    with pytest.raises(TypeError) as info:
        array.is_lower_bound("hello")
    assert ("The index argument should be an integer but found 'str'."
            in str(info.value))

    # not a range node at index 0
    assert not array.is_lower_bound(0)

    # range node does not have a binary operator for its start value
    array.children[0] = Range.create(one, one, one)
    assert not array.is_lower_bound(0)

    # range node lbound references a different array
    array2 = ArrayReference.create(DataSymbol("test2",
                                              ArrayType(REAL_TYPE, [10])),
                                   [one])
    operator = BinaryOperation.create(
        BinaryOperation.Operator.LBOUND, array2,
        Literal("1", INTEGER_TYPE))
    array.children[0] = Range.create(operator, one, one)
    assert not array.is_lower_bound(0)

    # range node lbound references a different index
    operator = BinaryOperation.create(
        BinaryOperation.Operator.LBOUND, array,
        Literal("2", INTEGER_TYPE))
    array.children[0] = Range.create(operator, one, one)
    assert not array.is_lower_bound(0)

    # all is well
    operator = BinaryOperation.create(
        BinaryOperation.Operator.LBOUND, array, one)
    array.children[0] = Range.create(operator, one, one)
    assert array.is_lower_bound(0)
Пример #13
0
def test_where_array_notation_rank():
    ''' Test that the _array_notation_rank() utility raises the expected
    errors when passed an unsupported Array object.
    '''
    array_type = ArrayType(REAL_TYPE, [10])
    symbol = DataSymbol("my_array", array_type)
    my_array = ArrayReference(symbol)
    processor = Fparser2Reader()
    with pytest.raises(NotImplementedError) as err:
        processor._array_notation_rank(my_array)
    assert ("Array reference in the PSyIR must have at least one child but "
            "'my_array'" in str(err.value))
    from psyclone.psyir.nodes import Range
    array_type = ArrayType(REAL_TYPE, [10])
    my_array = ArrayReference.create(DataSymbol("my_array", array_type), [
        Range.create(Literal("1", INTEGER_TYPE), Literal("10", INTEGER_TYPE))
    ])
    with pytest.raises(NotImplementedError) as err:
        processor._array_notation_rank(my_array)
    assert ("Only array notation of the form my_array(:, :, ...) is "
            "supported." in str(err.value))
Пример #14
0
def test_array_create_invalid1():
    '''Test that the create method in the ArrayReference class raises an
    exception if the provided symbol is not an array.

    '''
    symbol_i = DataSymbol("i", INTEGER_SINGLE_TYPE)
    symbol_j = DataSymbol("j", INTEGER_SINGLE_TYPE)
    symbol_temp = DataSymbol("temp", REAL_SINGLE_TYPE)
    children = [Reference(symbol_i), Reference(symbol_j),
                Literal("1", INTEGER_SINGLE_TYPE)]
    with pytest.raises(GenerationError) as excinfo:
        _ = ArrayReference.create(symbol_temp, children)
    assert ("expecting the symbol to be an array, not a scalar."
            in str(excinfo.value))
Пример #15
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))
Пример #16
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))
Пример #17
0
def test_array_create():
    '''Test that the create method in the ArrayReference class correctly
    creates an ArrayReference instance.

    '''
    array_type = ArrayType(REAL_SINGLE_TYPE, [10, 10, 10])
    symbol_temp = DataSymbol("temp", array_type)
    symbol_i = DataSymbol("i", INTEGER_SINGLE_TYPE)
    symbol_j = DataSymbol("j", INTEGER_SINGLE_TYPE)
    children = [Reference(symbol_i), Reference(symbol_j),
                Literal("1", INTEGER_SINGLE_TYPE)]
    array = ArrayReference.create(symbol_temp, children)
    check_links(array, children)
    result = FortranWriter().arrayreference_node(array)
    assert result == "temp(i,j,1)"
Пример #18
0
def test_call_create(cls):
    '''Test that the create method creates a valid call with arguments'''

    routine = RoutineSymbol("ellie")
    array_type = ArrayType(INTEGER_TYPE, shape=[10, 20])
    arguments = [
        Reference(DataSymbol("arg1", INTEGER_TYPE)),
        ArrayReference(DataSymbol("arg2", array_type))
    ]
    call = cls.create(routine, arguments)
    # pylint: disable=unidiomatic-typecheck
    assert type(call) is cls
    assert call.routine is routine
    for idx, child, in enumerate(call.children):
        assert child is arguments[idx]
        assert child.parent is call
Пример #19
0
def test_array_children_validation():
    '''Test that children added to Array are validated. Array accepts
    DataNodes and Range children.'''
    array_type = ArrayType(REAL_SINGLE_TYPE, shape=[5, 5])
    array = ArrayReference(DataSymbol("rname", array_type))
    datanode1 = Literal("1", INTEGER_SINGLE_TYPE)
    erange = Range()
    assignment = Assignment()

    # Invalid child
    with pytest.raises(GenerationError) as excinfo:
        array.addchild(assignment)
    assert ("Item 'Assignment' can't be child 0 of 'ArrayReference'. The valid"
            " format is: '[DataNode | Range]+'." in str(excinfo.value))

    # Valid children
    array.addchild(datanode1)
    array.addchild(erange)
Пример #20
0
def test_array_validate_index():
    '''Test that the validate_index utility function behaves as expected.'''
    array = ArrayReference.create(
        DataSymbol("test", ArrayType(REAL_TYPE, [10])),
        [Literal("1", INTEGER_TYPE)])
    with pytest.raises(TypeError) as info:
        array._validate_index("hello")
    assert ("The index argument should be an integer but found 'str'."
            in str(info.value))

    with pytest.raises(ValueError) as info:
        array._validate_index(1)
    assert ("In ArrayReference 'test' the specified index '1' must be less "
            "than the number of dimensions '1'." in str(info.value))

    array._validate_index(0)
    array._validate_index(-1)
Пример #21
0
def test_array_create_invalid2():
    '''Test that the create method in the ArrayReference class raises an
    exception if the number of dimension in the provided symbol is different
    to the number of indices provided to the create method.

    '''
    array_type = ArrayType(REAL_SINGLE_TYPE, [10])
    symbol_temp = DataSymbol("temp", array_type)
    symbol_i = DataSymbol("i", INTEGER_SINGLE_TYPE)
    symbol_j = DataSymbol("j", INTEGER_SINGLE_TYPE)
    children = [Reference(symbol_i), Reference(symbol_j),
                Literal("1", INTEGER_SINGLE_TYPE)]
    with pytest.raises(GenerationError) as excinfo:
        _ = ArrayReference.create(symbol_temp, children)
    assert ("the symbol should have the same number of dimensions as indices "
            "(provided in the 'indices' argument). Expecting '3' but found "
            "'1'." in str(excinfo.value))
Пример #22
0
def test_reference():
    '''Test that the common reference visitor writes the referenced symbol name
    or raises an error if the node is not Leaf node reference.

    '''
    # Generate PSyIR Reference
    test_visitor = PSyIRVisitor()
    reference = Reference(DataSymbol('a', REAL_TYPE))
    result = test_visitor(reference)
    assert result == "a"

    # Generate PSyIR ArrayReference
    reference2 = ArrayReference.create(
        DataSymbol('b', ArrayType(REAL_TYPE, shape=[1])), [reference])
    with pytest.raises(VisitorError) as err:
        result = test_visitor(reference2)
    assert "Expecting a Reference with no children but found: " \
        in str(err.value)
Пример #23
0
def create_array_x(symbol_table):
    '''Utility routine that creates and returns an array reference to a
    one-dimensional array "x". The array reference accesses all of the
    elements in the array dimension using a range node. In Fortran
    array notation this is "x(:)".

    :param symbol_table: the symbol table to which we add the array \
        symbol.
    :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable`

    :returns: an array reference that accesses all elements of the \
        array "x".
    :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference`

    '''
    array_symbol = DataSymbol("x", ArrayType(REAL_TYPE, [10]))
    symbol_table.add(array_symbol)
    return ArrayReference.create(array_symbol, [create_range(array_symbol, 1)])
Пример #24
0
def create_array_y_2d_slice(symbol_table):
    '''Utility routine that creates and returns an array reference to a 2
    dimensional array "y". The array reference accesses all elements
    in the 1st and 2nd dimensions of the array using range nodes. In
    Fortran array notation this is "y(:,:)".

    :param symbol_table: the symbol table to which we add the array \
        symbol.
    :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable`

    :returns: an array reference that accesses all elements of the 1st \
        and 2nd dimensions of the "y" array.
    :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference`

    '''
    array_symbol = DataSymbol("y2", ArrayType(REAL_TYPE, [20, 10]))
    symbol_table.add(array_symbol)
    return ArrayReference.create(array_symbol, [create_range(array_symbol, 1),
                                                create_range(array_symbol, 2)])
Пример #25
0
def test_array_indices():
    ''' Tests for the indices property (provided by the ArrayMixin class). '''
    one = Literal("1", INTEGER_TYPE)
    array = ArrayReference.create(
        DataSymbol("test", ArrayType(REAL_TYPE, [10])), [one])
    assert array.indices == [one]
    # Add an invalid child
    array._children = [one.copy(), "hello"]
    with pytest.raises(InternalError) as err:
        _ = array.indices
    assert ("ArrayReference malformed or incomplete: child 1 must by a "
            "psyir.nodes.DataNode or Range representing an array-index "
            "expression but found 'str'" in str(err.value))
    # Remove the children altogether
    array._children = []
    with pytest.raises(InternalError) as err:
        _ = array.indices
    assert ("ArrayReference malformed or incomplete: must have one or more "
            "children representing array-index expressions but found none"
            in str(err.value))
Пример #26
0
def test_validate5():
    '''Check that the Matmul2Code validate method raises the expected
    exception when the supplied node is a MATMUL binary operation but
    either or both arguments are not references.

    '''
    trans = Matmul2CodeTrans()
    array_type = ArrayType(REAL_TYPE, [10])
    array = ArrayReference.create(DataSymbol("x", array_type),
                                  [Literal("10", INTEGER_TYPE)])
    mult = BinaryOperation.create(
        BinaryOperation.Operator.MUL, array, array)
    matmul = BinaryOperation.create(
        BinaryOperation.Operator.MATMUL, mult, mult)
    _ = Assignment.create(array, matmul)
    with pytest.raises(TransformationError) as excinfo:
        trans.validate(matmul)
    assert ("Expected children of a MATMUL BinaryOperation to be references, "
            "but found 'BinaryOperation', 'BinaryOperation'."
            in str(excinfo.value))
Пример #27
0
def test_range_view(capsys):
    ''' Check that calling view() on an array with a child Range works
    as expected. '''
    # Create the PSyIR for 'my_array(1, 1:10)'
    erange = Range.create(Literal("1", INTEGER_SINGLE_TYPE),
                          Literal("10", INTEGER_SINGLE_TYPE))
    array_type = ArrayType(REAL_SINGLE_TYPE, [10, 10])
    array = ArrayReference.create(DataSymbol("my_array", array_type),
                                  [Literal("1", INTEGER_SINGLE_TYPE), erange])
    array.view()
    stdout, _ = capsys.readouterr()
    arrayref = colored("ArrayReference", ArrayReference._colour)
    literal = colored("Literal", Literal._colour)
    rangestr = colored("Range", Range._colour)
    indent = "    "
    assert (arrayref + "[name:'my_array']\n" + indent + literal +
            "[value:'1', Scalar<INTEGER, SINGLE>]\n" + indent + rangestr +
            "[]\n" + 2 * indent + literal +
            "[value:'1', Scalar<INTEGER, SINGLE>]\n" + 2 * indent + literal +
            "[value:'10', Scalar<INTEGER, SINGLE>]\n" + 2 * indent + literal +
            "[value:'1', Scalar<INTEGER, UNDEFINED>]\n" in stdout)
Пример #28
0
 def gen_code(self, parent):
     ''' Work out the appropriate loop bounds and then call the base
         class to generate the code '''
     self.start_expr = Literal("1", INTEGER_TYPE, parent=self)
     if self._loop_type == "colours":
         self.stop_expr = Reference(DataSymbol("ncolour", INTEGER_TYPE),
                                    parent=self)
     elif self._loop_type == "colour":
         self.stop_expr = ArrayReference(DataSymbol("ncp_ncolour",
                                                    INTEGER_TYPE),
                                         parent=self)
         self.stop_expr.addchild(Reference(
             DataSymbol("colour", INTEGER_TYPE)),
                                 parent=self.stop_expr)
     else:
         # This is a hack as the name is not a valid DataSymbol, it
         # is a call to a type-bound function.
         self.stop_expr = Reference(DataSymbol(
             self.field_name + "%get_ncell()", INTEGER_TYPE),
                                    parent=self)
     Loop.gen_code(self, parent)
Пример #29
0
def create_array_y(symbol_table):
    '''Utility routine that creates and returns an array reference to a
    two-dimensional array "y". The array reference accesses all
    elements in the 2nd dimension of the array using a range node and
    the n'th element of the 1st dimension. In Fortran array notation
    this is "y(n,:)".

    :param symbol_table: the symbol table to which we add the array \
        symbol and access the symbol "n".
    :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable`

    :returns: an array reference that accesses all elements of the \
        2nd dimension of array "y" and the n'th element of its 1st \
        dimension.
    :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference`

    '''
    array_symbol = DataSymbol("y", ArrayType(REAL_TYPE, [10, 10]))
    symbol_table.add(array_symbol)
    return ArrayReference.create(array_symbol,
                                 [Reference(symbol_table.lookup("n")),
                                  create_range(array_symbol, 2)])
Пример #30
0
def create_array_y_slice_subset(symbol_table):
    '''Utility routine that creates and returns an array reference to a 2
    dimensional array "y". The array reference accesses elements 2 to
    "n" step 2 in the arrays 2nd dimension using a range node and the
    n'th element of the 1st dimension. In Fortran array notation this
    is "y(n,2:n:2)".

    :param symbol_table: the symbol table to which we add the array \
        symbol and access the symbol "n".
    :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable`

    :returns: an array reference that accesses elements 2 to "n" step \
        2 in the array "y"'s 2nd dimension and the n'th element of its \
        1st dimension.
    :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference`

    '''
    array_symbol = DataSymbol("y3", ArrayType(REAL_TYPE, [10, 10]))
    symbol_table.add(array_symbol)
    symbol_n = symbol_table.lookup("n")
    return ArrayReference.create(
        array_symbol, [Reference(symbol_n),
                       create_stepped_range(symbol_n)])