Example #1
0
def test_naryoperation_node_str():
    ''' Check the node_str method of the Nary Operation class.'''
    nary_operation = NaryOperation(NaryOperation.Operator.MAX)
    nary_operation.addchild(
        Literal("1", INTEGER_SINGLE_TYPE, parent=nary_operation))
    nary_operation.addchild(
        Literal("1", INTEGER_SINGLE_TYPE, parent=nary_operation))
    nary_operation.addchild(
        Literal("1", INTEGER_SINGLE_TYPE, parent=nary_operation))

    coloredtext = colored("NaryOperation", NaryOperation._colour)
    assert coloredtext + "[operator:'MAX']" in nary_operation.node_str()
Example #2
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
Example #3
0
def test_operations_can_be_copied():
    ''' Test that an operation can be copied. '''

    operands = [Reference(DataSymbol("tmp1", REAL_SINGLE_TYPE)),
                Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                Reference(DataSymbol("tmp3", REAL_SINGLE_TYPE))]
    operation = NaryOperation.create(NaryOperation.Operator.MAX, operands)

    operation1 = operation.copy()
    assert isinstance(operation1, NaryOperation)
    assert operation1 is not operation
    assert operation1.operator is NaryOperation.Operator.MAX
    assert operation1.children[0].symbol.name == "tmp1"
    assert operation1.children[0] is not operands[0]
    assert operation1.children[0].parent is operation1
    assert operation1.children[1].symbol.name == "tmp2"
    assert operation1.children[1] is not operands[1]
    assert operation1.children[1].parent is operation1
    assert operation1.children[2].symbol.name == "tmp3"
    assert operation1.children[2] is not operands[2]
    assert operation1.children[2].parent is operation1
    assert len(operation1.children) == 3
    assert len(operation.children) == 3

    # Modifying the new operation does not affect the original
    operation1._operator = NaryOperation.Operator.MIN
    operation1.children.pop()
    assert len(operation1.children) == 2
    assert len(operation.children) == 3
    assert operation1.operator is NaryOperation.Operator.MIN
    assert operation.operator is NaryOperation.Operator.MAX
Example #4
0
def test_naryoperation_node_str():
    ''' Check the node_str method of the Nary Operation class.'''
    from psyclone.psyir.nodes.node import colored, SCHEDULE_COLOUR_MAP
    nary_operation = NaryOperation(NaryOperation.Operator.MAX)
    nary_operation.addchild(
        Literal("1", INTEGER_SINGLE_TYPE, parent=nary_operation))
    nary_operation.addchild(
        Literal("1", INTEGER_SINGLE_TYPE, parent=nary_operation))
    nary_operation.addchild(
        Literal("1", INTEGER_SINGLE_TYPE, parent=nary_operation))

    coloredtext = colored("NaryOperation", SCHEDULE_COLOUR_MAP["Operation"])
    assert coloredtext + "[operator:'MAX']" in nary_operation.node_str()
Example #5
0
def test_naryoperation_create_invalid():
    '''Test that the create method in an NaryOperation class raises the
    expected exception if the provided input is invalid.

    '''
    # oper not an NaryOperation.Operator
    with pytest.raises(GenerationError) as excinfo:
        _ = NaryOperation.create("invalid", [])
    assert ("oper argument in create method of NaryOperation class should "
            "be a PSyIR NaryOperation Operator but found 'str'."
            in str(excinfo.value))

    # children not a list
    with pytest.raises(GenerationError) as excinfo:
        _ = NaryOperation.create(NaryOperation.Operator.SUM, "invalid")
    assert ("children argument in create method of NaryOperation class should "
            "be a list but found 'str'." in str(excinfo.value))
Example #6
0
def test_naryoperation_create():
    '''Test that the create method in the NaryOperation class correctly
    creates an NaryOperation instance.

    '''
    children = [Reference(DataSymbol("tmp1", REAL_SINGLE_TYPE)),
                Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                Reference(DataSymbol("tmp3", REAL_SINGLE_TYPE))]
    oper = NaryOperation.Operator.MAX
    naryoperation = NaryOperation.create(oper, children)
    check_links(naryoperation, children)
    result = FortranWriter().naryoperation_node(naryoperation)
    assert result == "MAX(tmp1, tmp2, tmp3)"
Example #7
0
def test_naryoperation_can_be_printed():
    '''Test that an Nary Operation instance can always be printed (i.e. is
    initialised fully)'''
    nary_operation = NaryOperation(NaryOperation.Operator.MAX)
    assert "NaryOperation[operator:'MAX']" in str(nary_operation)
    nary_operation.addchild(
        Literal("1", INTEGER_SINGLE_TYPE, parent=nary_operation))
    nary_operation.addchild(
        Literal("2", INTEGER_SINGLE_TYPE, parent=nary_operation))
    nary_operation.addchild(
        Literal("3", INTEGER_SINGLE_TYPE, parent=nary_operation))
    # Check the node children are also printed
    assert ("Literal[value:'1', Scalar<INTEGER, SINGLE>]\n"
            in str(nary_operation))
    assert ("Literal[value:'2', Scalar<INTEGER, SINGLE>]\n"
            in str(nary_operation))
    assert ("Literal[value:'3', Scalar<INTEGER, SINGLE>]"
            in str(nary_operation))
Example #8
0
def test_naryoperation_children_validation():
    '''Test that children added to NaryOperation are validated. NaryOperations
    accepts DataNodes nodes as children.

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

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

    # Statements are not valid
    with pytest.raises(GenerationError) as excinfo:
        nary.addchild(statement)
    assert ("Item 'Return' can't be child 3 of 'NaryOperation'. The valid "
            "format is: '[DataNode]+'.") in str(excinfo.value)
Example #9
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
Example #10
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
Example #11
0
INT_ZERO = Literal("0", INTEGER_SINGLE_TYPE)
INT_ONE = Literal("1", INTEGER8_TYPE)
TMP1 = Reference(ARG1)
TMP2 = 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 = Array.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)