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()
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
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
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()
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))
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)"
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))
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)
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
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
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)