Exemple #1
0
def test_range_setter_errors(prop):
    ''' Check that the various setters reject values that are not sub-classes
    of Node. '''
    # We use exec() so that we can use the pytest parameterisation of the
    # various properties we want to test
    # pylint:disable=exec-used,unused-variable
    erange = Range()
    with pytest.raises(TypeError) as err:
        exec("erange." + prop + " = 1")
    assert "must be a sub-class of Node but got" in str(err.value)
    val = Literal("1.0", REAL_SINGLE_TYPE)
    with pytest.raises(TypeError) as err:
        exec("erange." + prop + " = val")
    assert ("value of a Range is a Literal then it must be of type "
            "INTEGER but got Scalar<REAL, SINGLE>" in str(err.value))
Exemple #2
0
def test_range_literals_props():
    ''' Test that the properties of a Range return what we expect
    when the start, stop and step are Literals. '''
    start = Literal("10", INTEGER_SINGLE_TYPE)
    stop = Literal("20", INTEGER_SINGLE_TYPE)
    erange = Range.create(start, stop)
    assert erange.children[0] is start
    assert erange.children[1] is stop
    # We didn't supply an increment so check that one was created
    assert isinstance(erange.children[2], Literal)
    assert (erange.children[2].datatype.intrinsic ==
            ScalarType.Intrinsic.INTEGER)
    assert (erange.children[2].datatype.precision ==
            ScalarType.Precision.UNDEFINED)
    assert erange.children[2].value == "1"
    # Create another one with a specified step
    start = Literal("10", INTEGER_SINGLE_TYPE)
    stop = Literal("20", INTEGER_SINGLE_TYPE)
    erange2 = Range.create(start, stop, Literal("5", INTEGER_SINGLE_TYPE))
    assert erange2.children[0] is start
    assert erange2.children[1] is stop
    assert (erange2.children[2].datatype.precision ==
            ScalarType.Precision.SINGLE)
    assert erange2.step.value == "5"
Exemple #3
0
def test_range_out_of_order_setter():
    ''' Test that setting the start/stop/step props out of order raises the
    expected error. '''
    erange = Range()
    datanode1 = Literal("1", INTEGER_SINGLE_TYPE)
    datanode2 = Literal("2", INTEGER_SINGLE_TYPE)
    datanode3 = Literal("3", INTEGER_SINGLE_TYPE)

    # Stop before Start
    with pytest.raises(IndexError) as excinfo:
        erange.stop = datanode2
    assert ("The Stop value 'Literal[value:'2', Scalar<INTEGER, SINGLE>]' can"
            " not be inserted into range 'Range[]' before the Start value is "
            "provided." in str(excinfo.value))
    # Once start is added, setting it up again just replaces it
    erange.start = datanode1
    erange.start = datanode1
    assert len(erange.children) == 1
    # Now Stop can be accepted
    erange.stop = datanode2
    # Once added, setting it up again just replaces it
    erange.stop = datanode2
    assert len(erange.children) == 2

    # Step before Step
    del erange.children[1]
    with pytest.raises(IndexError) as excinfo:
        erange.step = datanode3
    assert ("The Step value 'Literal[value:'3', Scalar<INTEGER, SINGLE>]' can"
            " not be inserted into range 'Range[]' before the Start and Stop "
            "values are provided." in str(excinfo.value))
    erange.stop = datanode2
    erange.step = datanode3
    # Once added, setting it up again just replaces it
    erange.step = datanode3
    assert len(erange.children) == 3
Exemple #4
0
def create_stepped_range(symbol):
    '''Utility routine that creates and returns a Range Node that
    specifies a range from "2" to "symbol" step "2".

    :param symbol: the symbol representing the upper bound.
    :type symbol: :py:class:`psyclone.psyir.symbol.Symbol`

    :returns: a range node specifying a range from 2 to "symbol" with \
        a step of 2 for the supplied array dimension.
    :rtype: :py:class:`psyclone.psyir.nodes.Range`

    '''
    lbound = Literal("2", INTEGER_TYPE)
    ubound = Reference(symbol)
    step = Literal("2", INTEGER_TYPE)
    return Range.create(lbound, ubound, step)
Exemple #5
0
def test_sched_children_validation():
    '''Test that children added to Schedule are validated. Schedule accepts
    Statements as children.

    '''
    schedule = Schedule()
    statement = Assignment()
    nonstatement = Range()

    # Invalid child
    with pytest.raises(GenerationError) as excinfo:
        schedule.addchild(nonstatement)
    assert ("Item 'Range' can't be child 0 of 'Schedule'. The valid"
            " format is: '[Statement]*'." in str(excinfo.value))

    # Valid children
    schedule.addchild(statement)
Exemple #6
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 = Array(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)
Exemple #7
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 = Array(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 = Array.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))
Exemple #8
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)
Exemple #9
0
def create_range(array_symbol, dim):
    '''Utility routine that creates and returns a Range Node that
    specifies the full range of the supplied dimension (dim) in the
    array (array_symbol). This is done using the LBOUND and UBOUND
    intrinsics.

    :param array_symbol: the array of interest.
    :type array_symbol: :py:class:`psyclone.psyir.symbol.DataSymbol`
    :param int dim: the dimension of interest in the array.

    :returns: a range node specifying the full range of the supplied \
        array dimension.
    :rtype: :py:class:`psyclone.psyir.nodes.Range`

    '''
    int_dim = Literal(str(dim), INTEGER_TYPE)
    lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                    Reference(array_symbol), int_dim)
    ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                    Reference(array_symbol), int_dim)
    return Range.create(lbound, ubound)
Exemple #10
0
def test_apply4(tmpdir):
    '''Test that the matmul2code apply method produces the expected
    PSyIR. We use the Fortran backend to help provide the test for
    correctness. This example make the lhs be the same array as the
    second operand of the matmul (the vector in this case).

    '''
    trans = Matmul2CodeTrans()
    one = Literal("1", INTEGER_TYPE)
    five = Literal("5", INTEGER_TYPE)
    matmul = create_matmul()
    root = matmul.root
    assignment = matmul.parent
    vector = assignment.scope.symbol_table.lookup("y")
    assignment.children[0] = ArrayReference.create(
        vector, [Range.create(one, five, one.copy()),
                 one.copy()])
    trans.apply(matmul)
    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine my_kern()\n"
            "  integer, parameter :: idx = 3\n"
            "  real, dimension(5,10,15) :: x\n"
            "  real, dimension(10,20) :: y\n"
            "  real, dimension(10) :: result\n"
            "  integer :: i\n"
            "  integer :: j\n"
            "\n"
            "  do i = 1, 5, 1\n"
            "    y(i,1) = 0.0\n"
            "    do j = 1, 10, 1\n"
            "      y(i,1) = y(i,1) + x(i,j,idx) * y(j,idx)\n"
            "    enddo\n"
            "  enddo\n"
            "\n"
            "end subroutine my_kern" in result)
    assert Compile(tmpdir).string_compiles(result)
INT_ONE = Literal("1", INTEGER8_TYPE)

# Reference to the "flag" scalar component of FIELD_SYMBOL, "field%flag"
FLAG_REF = StructureReference.create(FIELD_SYMBOL, ["flag"])

# Reference to "field%grid%dx"
DX_REF = StructureReference.create(FIELD_SYMBOL, ["grid", "dx"])

# Array reference to component of derived type using a range
LBOUND = BinaryOperation.create(
    BinaryOperation.Operator.LBOUND,
    StructureReference.create(FIELD_SYMBOL, ["data"]), INT_ONE)
UBOUND = BinaryOperation.create(
    BinaryOperation.Operator.UBOUND,
    StructureReference.create(FIELD_SYMBOL, ["data"]), INT_ONE)
MY_RANGE = Range.create(LBOUND, UBOUND)

DATA_REF = StructureReference.create(FIELD_SYMBOL, [("data", [MY_RANGE])])

# Reference to "field%sub_meshes(1)%dx"
DX_REF2 = StructureReference.create(FIELD_SYMBOL, [("sub_meshes", [INT_ONE]),
                                                   "dx"])

# Reference to "chi(1)%sub_meshes(1)%dx"
DX_REF3 = ArrayOfStructuresReference.create(FIELD_BUNDLE_SYMBOL, [INT_ONE],
                                            [("sub_meshes", [INT_ONE]), "dx"])

ASSIGNMENTS = [
    Assignment.create(DX_REF, TWO),
    Assignment.create(FLAG_REF, INT_ONE),
    Assignment.create(DATA_REF, TWO),
Exemple #12
0
def test_range_str():
    ''' Check that node_str and str work correctly for a Range node. '''
    erange = Range()
    assert 'Range[]' in erange.node_str(colour=False)
    assert 'Range' in erange.node_str(colour=True)
    assert erange.node_str(colour=False) == str(erange)
Exemple #13
0
def test_array_is_full_range():
    '''Test that the is_full_range method in the Array Node works as
    expected. '''
    # pylint: disable=too-many-statements
    zero = Literal("0", INTEGER_SINGLE_TYPE)
    one = Literal("1", INTEGER_SINGLE_TYPE)
    array_type = ArrayType(REAL_SINGLE_TYPE, [10])
    symbol = DataSymbol("my_array", array_type)
    reference = Reference(symbol)
    lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND, reference,
                                    one)
    ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND, reference,
                                    one)
    symbol_error = DataSymbol("another_array", array_type)
    reference_error = Reference(symbol_error)

    # Index out of bounds
    array_reference = Array.create(symbol, [one])
    with pytest.raises(ValueError) as excinfo:
        array_reference.is_full_range(1)
    assert ("In Array 'my_array' the specified index '1' must be less than "
            "the number of dimensions '1'." in str(excinfo.value))

    # Array dimension is not a Range
    assert not array_reference.is_full_range(0)

    # Check LBOUND
    # Array dimension range lower bound is not a binary operation
    my_range = Range.create(one, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range lower bound is not an LBOUND binary operation
    my_range = Range.create(ubound, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range lower bound is an LBOUND binary operation
    # with the first value not being a reference
    lbound_error = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                          zero, zero)
    my_range = Range.create(lbound_error, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range lower bound is an LBOUND binary operation
    # with the first value being a reference to a different symbol
    lbound_error = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                          reference_error, zero)
    my_range = Range.create(lbound_error, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range lower bound is an LBOUND binary operation
    # with the second value not being a literal.
    lbound_error = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                          reference, reference)
    my_range = Range.create(lbound_error, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range lower bound is an LBOUND binary operation
    # with the second value not being an integer literal.
    lbound_error = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                          reference,
                                          Literal("1.0", REAL_SINGLE_TYPE))
    my_range = Range.create(lbound_error, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range lower bound is an LBOUND binary operation
    # with the second value being an integer literal with the wrong
    # value (should be 0 as this dimension index is 0).
    lbound_error = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                          reference, one)
    my_range = Range.create(lbound_error, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Check UBOUND
    # Array dimension range upper bound is not a binary operation
    my_range = Range.create(lbound, one, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range upper bound is not a UBOUND binary operation
    my_range = Range.create(lbound, lbound, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range upper bound is a UBOUND binary operation
    # with the first value not being a reference
    ubound_error = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                          zero, zero)
    my_range = Range.create(lbound, ubound_error, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range upper bound is a UBOUND binary operation
    # with the first value being a reference to a different symbol
    ubound_error = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                          reference_error, zero)
    my_range = Range.create(lbound, ubound_error, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range upper bound is a UBOUND binary operation
    # with the second value not being a literal.
    ubound_error = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                          reference, reference)
    my_range = Range.create(lbound, ubound_error, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range upper bound is a UBOUND binary operation
    # with the second value not being an integer literal.
    ubound_error = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                          reference,
                                          Literal("1.0", REAL_SINGLE_TYPE))
    my_range = Range.create(lbound, ubound_error, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range upper bound is a UBOUND binary operation
    # with the second value being an integer literal with the wrong
    # value (should be 1 as this dimension is 1).
    ubound_error = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                          reference, zero)
    my_range = Range.create(lbound, ubound_error, one)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Check Step
    # Array dimension range step is not a literal.
    my_range = Range.create(lbound, ubound, lbound)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range step is not an integer literal.
    my_range = Range.create(lbound, ubound, one)
    # We have to change this to a non-integer manually as the create
    # function only accepts integer literals for the step argument.
    my_range.children[2] = Literal("1.0", REAL_SINGLE_TYPE)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # Array dimension range step is is an integer literal with the
    # wrong value (not 1).
    my_range = Range.create(lbound, ubound, zero)
    array_reference = Array.create(symbol, [my_range])
    assert not array_reference.is_full_range(0)

    # All is as it should be.
    # The full range is covered so return true.
    my_range = Range.create(lbound, ubound, one)
    array_reference = Array.create(symbol, [my_range])
    assert array_reference.is_full_range(0)
Exemple #14
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.

    '''
    one = Literal("1.0", REAL_TYPE)
    int_one = Literal("1", INTEGER_TYPE)
    int_ten = Literal("10", INTEGER_TYPE)

    # lhs is an array reference with a range
    array_type = ArrayType(REAL_TYPE, [10, 10])
    symbol = DataSymbol("x", array_type)
    x_range = Range.create(int_one, int_ten.copy(), int_one.copy())
    array_ref = ArrayReference.create(symbol, [x_range, int_one.copy()])
    assignment = Assignment.create(array_ref, one.copy())
    assert assignment.is_array_range is True

    # Check when lhs consists of various forms of structure access
    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)
    # Create the definition of the 'field_type', contains array of grid_types
    field_type_def = StructureType.create([
        ("data", ArrayType(REAL_SINGLE_TYPE, [10]), Symbol.Visibility.PUBLIC),
        ("sub_meshes", ArrayType(grid_type_symbol,
                                 [3]), Symbol.Visibility.PUBLIC)
    ])
    field_type_symbol = DataTypeSymbol("field_type", field_type_def)
    field_symbol = DataSymbol("wind", field_type_symbol)

    # Array reference to component of derived type using a range
    lbound = BinaryOperation.create(
        BinaryOperation.Operator.LBOUND,
        StructureReference.create(field_symbol, ["data"]), int_one.copy())
    ubound = BinaryOperation.create(
        BinaryOperation.Operator.UBOUND,
        StructureReference.create(field_symbol, ["data"]), int_one.copy())
    my_range = Range.create(lbound, ubound)

    data_ref = StructureReference.create(field_symbol, [("data", [my_range])])
    assign = Assignment.create(data_ref, one.copy())
    assert assign.is_array_range is True

    # Access to slice of 'sub_meshes': wind%sub_meshes(1:3)%dx = 1.0
    sub_range = Range.create(int_one.copy(), Literal("3", INTEGER_TYPE))
    dx_ref = StructureReference.create(field_symbol,
                                       [("sub_meshes", [sub_range]), "dx"])
    sub_assign = Assignment.create(dx_ref, one.copy())
    assert sub_assign.is_array_range is True

    # Create an array of these derived types and assign to a slice:
    # chi(1:10)%data(1) = 1.0
    field_bundle_symbol = DataSymbol("chi", ArrayType(field_type_symbol, [3]))
    fld_range = Range.create(int_one.copy(), Literal("10", INTEGER_TYPE))
    fld_ref = ArrayOfStructuresReference.create(field_bundle_symbol,
                                                [fld_range],
                                                [("data", [int_one.copy()])])
    fld_assign = Assignment.create(fld_ref, one.copy())
    assert fld_assign.is_array_range is True

    # When the slice has two operator ancestors, none of which are a reduction
    # e.g y(1, INT(ABS(map(:, 1)))) = 1.0
    int_array_type = ArrayType(INTEGER_SINGLE_TYPE, [10, 10])
    map_sym = DataSymbol("map", int_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)
    abs_op = UnaryOperation.create(
        UnaryOperation.Operator.ABS,
        ArrayReference.create(map_sym, [my_range1, int_one.copy()]))
    int_op = UnaryOperation.create(UnaryOperation.Operator.INT, abs_op)
    assignment = Assignment.create(
        ArrayReference.create(symbol, [int_one.copy(), int_op]), one.copy())
    assert assignment.is_array_range is True
Exemple #15
0
def create_psyir_tree():
    ''' Create an example PSyIR Tree.

    :returns: an example PSyIR tree.
    :rtype: :py:class:`psyclone.psyir.nodes.Container`

    '''
    # Symbol table, symbols and scalar datatypes
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    symbol_table.specify_argument_list([arg1])
    tmp_symbol = symbol_table.new_symbol(symbol_type=DataSymbol,
                                         datatype=REAL_DOUBLE_TYPE)
    index_symbol = symbol_table.new_symbol(root_name="i",
                                           symbol_type=DataSymbol,
                                           datatype=INTEGER4_TYPE)
    real_kind = symbol_table.new_symbol(root_name="RKIND",
                                        symbol_type=DataSymbol,
                                        datatype=INTEGER_TYPE,
                                        constant_value=8)
    routine_symbol = RoutineSymbol("my_sub")

    # Array using precision defined by another symbol
    scalar_type = ScalarType(ScalarType.Intrinsic.REAL, real_kind)
    array = symbol_table.new_symbol(root_name="a",
                                    symbol_type=DataSymbol,
                                    datatype=ArrayType(scalar_type, [10]))

    # Make generators for nodes which do not have other Nodes as children,
    # with some predefined scalar datatypes
    def zero():
        return Literal("0.0", REAL_TYPE)

    def one():
        return Literal("1.0", REAL4_TYPE)

    def two():
        return Literal("2.0", scalar_type)

    def int_zero():
        return Literal("0", INTEGER_SINGLE_TYPE)

    def int_one():
        return Literal("1", INTEGER8_TYPE)

    def tmp1():
        return Reference(arg1)

    def tmp2():
        return Reference(tmp_symbol)

    # Unary Operation
    oper = UnaryOperation.Operator.SIN
    unaryoperation = UnaryOperation.create(oper, tmp2())

    # Binary Operation
    oper = BinaryOperation.Operator.ADD
    binaryoperation = BinaryOperation.create(oper, one(), unaryoperation)

    # Nary Operation
    oper = NaryOperation.Operator.MAX
    naryoperation = NaryOperation.create(oper, [tmp1(), tmp2(), one()])

    # Array reference using a range
    lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                    Reference(array), int_one())
    ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                    Reference(array), int_one())
    my_range = Range.create(lbound, ubound)
    tmparray = ArrayReference.create(array, [my_range])

    # Assignments
    assign1 = Assignment.create(tmp1(), zero())
    assign2 = Assignment.create(tmp2(), zero())
    assign3 = Assignment.create(tmp2(), binaryoperation)
    assign4 = Assignment.create(tmp1(), tmp2())
    assign5 = Assignment.create(tmp1(), naryoperation)
    assign6 = Assignment.create(tmparray, two())

    # Call
    call = Call.create(routine_symbol, [tmp1(), binaryoperation.copy()])

    # If statement
    if_condition = BinaryOperation.create(BinaryOperation.Operator.GT, tmp1(),
                                          zero())
    ifblock = IfBlock.create(if_condition, [assign3, assign4])

    # Loop
    loop = Loop.create(index_symbol, int_zero(), int_one(), int_one(),
                       [ifblock])

    # KernelSchedule
    kernel_schedule = KernelSchedule.create(
        "work", symbol_table, [assign1, call, assign2, loop, assign5, assign6])

    # Container
    container_symbol_table = SymbolTable()
    container = Container.create("CONTAINER", container_symbol_table,
                                 [kernel_schedule])

    # Import data from another container
    external_container = ContainerSymbol("some_mod")
    container_symbol_table.add(external_container)
    external_var = DataSymbol("some_var",
                              INTEGER_TYPE,
                              interface=GlobalInterface(external_container))
    container_symbol_table.add(external_var)
    routine_symbol.interface = GlobalInterface(external_container)
    container_symbol_table.add(routine_symbol)
    return container
Exemple #16
0
def test_range_children_validation():
    '''Test that children added to Range are validated. Range accepts
    3 DataNodes.

    '''
    erange = Range()
    datanode1 = Literal("1", INTEGER_SINGLE_TYPE)
    datanode2 = Literal("2", INTEGER_SINGLE_TYPE)
    datanode3 = Literal("3", INTEGER_SINGLE_TYPE)
    range2 = Range()

    # First child
    with pytest.raises(GenerationError) as excinfo:
        erange.addchild(range2)
    assert ("Item 'Range' can't be child 0 of 'Range'. The valid format is: "
            "'DataNode, DataNode, DataNode'." in str(excinfo.value))
    erange.addchild(datanode1)

    # Second child
    with pytest.raises(GenerationError) as excinfo:
        erange.addchild(range2)
    assert ("Item 'Range' can't be child 1 of 'Range'. The valid format is: "
            "'DataNode, DataNode, DataNode'." in str(excinfo.value))
    erange.addchild(datanode2)

    # Third child
    with pytest.raises(GenerationError) as excinfo:
        erange.addchild(range2)
    assert ("Item 'Range' can't be child 2 of 'Range'. The valid format is: "
            "'DataNode, DataNode, DataNode'." in str(excinfo.value))
    erange.addchild(datanode3)

    # Additional children
    with pytest.raises(GenerationError) as excinfo:
        erange.addchild(datanode1)
    assert ("Item 'Literal' can't be child 3 of 'Range'. The valid format is:"
            " 'DataNode, DataNode, DataNode'." in str(excinfo.value))
Exemple #17
0
def create_psyir_tree():
    ''' Create an example PSyIR Tree.

    :returns: an example PSyIR tree.
    :rtype: :py:class:`psyclone.psyir.nodes.Container`

    '''
    # Symbol table, symbols and scalar datatypes
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    symbol_table.specify_argument_list([arg1])
    tmp_symbol = symbol_table.new_symbol(symbol_type=DataSymbol,
                                         datatype=REAL_DOUBLE_TYPE)
    index_symbol = symbol_table.new_symbol(root_name="i",
                                           symbol_type=DataSymbol,
                                           datatype=INTEGER4_TYPE)
    real_kind = symbol_table.new_symbol(root_name="RKIND",
                                        symbol_type=DataSymbol,
                                        datatype=INTEGER_TYPE,
                                        constant_value=8)
    routine_symbol = RoutineSymbol("my_sub")

    # Array using precision defined by another symbol
    scalar_type = ScalarType(ScalarType.Intrinsic.REAL, real_kind)
    array = symbol_table.new_symbol(root_name="a",
                                    symbol_type=DataSymbol,
                                    datatype=ArrayType(scalar_type, [10]))

    # Nodes which do not have Nodes as children and (some) predefined
    # scalar datatypes
    # TODO: Issue #1136 looks at how to avoid all of the _x versions
    zero_1 = Literal("0.0", REAL_TYPE)
    zero_2 = Literal("0.0", REAL_TYPE)
    zero_3 = Literal("0.0", REAL_TYPE)
    one_1 = Literal("1.0", REAL4_TYPE)
    one_2 = Literal("1.0", REAL4_TYPE)
    one_3 = Literal("1.0", REAL4_TYPE)
    two = Literal("2.0", scalar_type)
    int_zero = Literal("0", INTEGER_SINGLE_TYPE)
    int_one_1 = Literal("1", INTEGER8_TYPE)
    int_one_2 = Literal("1", INTEGER8_TYPE)
    int_one_3 = Literal("1", INTEGER8_TYPE)
    int_one_4 = Literal("1", INTEGER8_TYPE)
    tmp1_1 = Reference(arg1)
    tmp1_2 = Reference(arg1)
    tmp1_3 = Reference(arg1)
    tmp1_4 = Reference(arg1)
    tmp1_5 = Reference(arg1)
    tmp1_6 = Reference(arg1)
    tmp2_1 = Reference(tmp_symbol)
    tmp2_2 = Reference(tmp_symbol)
    tmp2_3 = Reference(tmp_symbol)
    tmp2_4 = Reference(tmp_symbol)
    tmp2_5 = Reference(tmp_symbol)
    tmp2_6 = Reference(tmp_symbol)

    # Unary Operation
    oper = UnaryOperation.Operator.SIN
    unaryoperation_1 = UnaryOperation.create(oper, tmp2_1)
    unaryoperation_2 = UnaryOperation.create(oper, tmp2_2)

    # Binary Operation
    oper = BinaryOperation.Operator.ADD
    binaryoperation_1 = BinaryOperation.create(oper, one_1, unaryoperation_1)
    binaryoperation_2 = BinaryOperation.create(oper, one_2, unaryoperation_2)

    # Nary Operation
    oper = NaryOperation.Operator.MAX
    naryoperation = NaryOperation.create(oper, [tmp1_1, tmp2_3, one_3])

    # Array reference using a range
    lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                    Reference(array), int_one_1)
    ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                    Reference(array), int_one_2)
    my_range = Range.create(lbound, ubound)
    tmparray = ArrayReference.create(array, [my_range])

    # Assignments
    assign1 = Assignment.create(tmp1_2, zero_1)
    assign2 = Assignment.create(tmp2_4, zero_2)
    assign3 = Assignment.create(tmp2_5, binaryoperation_1)
    assign4 = Assignment.create(tmp1_3, tmp2_6)
    assign5 = Assignment.create(tmp1_4, naryoperation)
    assign6 = Assignment.create(tmparray, two)

    # Call
    call = Call.create(routine_symbol, [tmp1_5, binaryoperation_2])

    # If statement
    if_condition = BinaryOperation.create(BinaryOperation.Operator.GT, tmp1_6,
                                          zero_3)
    ifblock = IfBlock.create(if_condition, [assign3, assign4])

    # Loop
    loop = Loop.create(index_symbol, int_zero, int_one_3, int_one_4, [ifblock])

    # KernelSchedule
    kernel_schedule = KernelSchedule.create(
        "work", symbol_table, [assign1, call, assign2, loop, assign5, assign6])

    # Container
    container_symbol_table = SymbolTable()
    container = Container.create("CONTAINER", container_symbol_table,
                                 [kernel_schedule])

    # Import data from another container
    external_container = ContainerSymbol("some_mod")
    container_symbol_table.add(external_container)
    external_var = DataSymbol("some_var",
                              INTEGER_TYPE,
                              interface=GlobalInterface(external_container))
    container_symbol_table.add(external_var)
    routine_symbol.interface = GlobalInterface(external_container)
    container_symbol_table.add(routine_symbol)
    return container
Exemple #18
0
def test_same_range():
    '''Test that the same_range utility function behaves in the expected
    way.

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

    array_type = ArrayType(REAL_TYPE, [10])
    array_value = Array.create(DataSymbol("dummy", array_type),
                               children=[DataNode("x")])
    array_range = Array.create(DataSymbol("dummy", array_type),
                               children=[Range()])

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

    with pytest.raises(TypeError) as info:
        ArrayRange2LoopTrans.same_range(array_value, 1, None, None)
    assert ("The third argument to the same_range() method should be an "
            "Array but found 'NoneType'." in str(info.value))

    with pytest.raises(TypeError) as info:
        ArrayRange2LoopTrans.same_range(array_value, 1, array_value, None)
    assert ("The fourth argument to the same_range() method should be an "
            "int but found 'NoneType'." in str(info.value))

    with pytest.raises(IndexError) as info:
        ArrayRange2LoopTrans.same_range(array_value, 1, array_value, 2)
    assert ("The value of the second argument to the same_range() method "
            "'1' should be less than the number of dimensions '1' in the "
            "associated array 'array1'." in str(info.value))

    with pytest.raises(IndexError) as info:
        ArrayRange2LoopTrans.same_range(array_value, 0, array_value, 2)
    assert ("The value of the fourth argument to the same_range() method "
            "'2' should be less than the number of dimensions '1' in the "
            "associated array 'array2'." in str(info.value))

    with pytest.raises(TypeError) as info:
        ArrayRange2LoopTrans.same_range(array_value, 0, array_value, 0)
    assert ("The child of the first array argument at the specified index (0) "
            "should be a Range node, but found 'DataNode'" in str(info.value))

    with pytest.raises(TypeError) as info:
        ArrayRange2LoopTrans.same_range(array_range, 0, array_value, 0)
    assert ("The child of the second array argument at the specified index "
            "(0) should be a Range node, but found 'DataNode'"
            in str(info.value))

    # lower bounds both use lbound, upper bounds both use ubound and
    # step is the same so everything matches.
    array_x = create_array_x(SymbolTable())
    array_x_2 = create_array_x(SymbolTable())
    assert ArrayRange2LoopTrans.same_range(array_x, 0, array_x_2, 0) is True

    # steps are different (calls string_compare)
    tmp = array_x_2.children[0].step
    array_x_2.children[0].step = Literal("2", INTEGER_TYPE)
    assert ArrayRange2LoopTrans.same_range(array_x, 0, array_x_2, 0) is False

    # Put step value back to what it was in case it affects the ubound
    # and lbound tests
    array_x_2.children[0].step = tmp

    # one of upper bounds uses ubound, other does not
    tmp1 = array_x_2.children[0].stop
    array_x_2.children[0].stop = Literal("2", INTEGER_TYPE)
    assert ArrayRange2LoopTrans.same_range(array_x, 0, array_x_2, 0) is False

    # neither use upper bound and are different (calls string_compare)
    tmp2 = array_x.children[0].stop
    array_x.children[0].stop = Literal("1", INTEGER_TYPE)
    assert ArrayRange2LoopTrans.same_range(array_x, 0, array_x_2, 0) is False

    # Put upper bounds back to what they were in case they affect the
    # lbound tests
    array_x_2.children[0].stop = tmp1
    array_x.children[0].stop = tmp2

    # one of lower bounds uses lbound, other does not
    array_x_2.children[0].start = Literal("1", INTEGER_TYPE)
    assert ArrayRange2LoopTrans.same_range(array_x, 0, array_x_2, 0) is False

    # neither use lower bound and are different (calls string_compare)
    array_x.children[0].start = Literal("2", INTEGER_TYPE)
    assert ArrayRange2LoopTrans.same_range(array_x, 0, array_x_2, 0) is False