def lower_to_language_level(self): '''Transform this node and its children into an appropriate Call node. ''' self.create_psylayer_symbols() arguments = [] arguments_str = [] for kern in self.children: for arg in kern.children: if isinstance(arg, Literal): # Literals are not passed by argument. pass elif isinstance(arg, (Reference, ArrayReference)): # TODO #753 use a better check for equivalence (math_equal) if str(arg).lower() not in arguments_str: arguments_str.append(str(arg).lower()) arguments.append(arg.copy()) else: raise GenerationError( "Expected Algorithm-layer kernel arguments to be " "a literal, reference or array reference, but " "found '{0}'.".format(type(arg).__name__)) symbol_table = self.scope.symbol_table routine_symbol = self.psylayer_routine_symbol container_symbol = routine_symbol.interface.container_symbol symbol_table.add(container_symbol) symbol_table.add(routine_symbol) call = Call.create(routine_symbol, arguments) self.replace_with(call)
def test_call_error2(): '''Test that the appropriate exception is raised if the arguments argument to the create method is not a list''' routine = RoutineSymbol("isaac") with pytest.raises(GenerationError) as info: _ = Call.create(routine, None) assert ("Call create arguments argument should be a list but found " "'NoneType'." in str(info.value))
def test_call_create_error1(): '''Test that the appropriate exception is raised if the routine argument to the create method is not a RoutineSymbol. ''' with pytest.raises(GenerationError) as info: _ = Call.create(None, []) assert ("Call create routine argument should be a RoutineSymbol but " "found 'NoneType'." in str(info.value))
def test_call_init_error(): '''Test that the appropriate exception is raised if the routine argument is not a RoutineSymbol. ''' with pytest.raises(TypeError) as info: _ = Call(None) assert ("Call routine argument should be a RoutineSymbol but found " "'NoneType'." in str(info.value))
def test_call_init(): '''Test that a Call can be created as expected. Also test the routine property. ''' # routine argument routine = RoutineSymbol("jo") call = Call(routine) assert call._routine is routine assert call.routine is call._routine assert call.parent is None assert call.children == [] # optional parent argument parent = Schedule() call = Call(routine, parent=parent) assert call.routine is routine assert call.parent is parent assert call.children == []
def _parse_args(code_block, fp2_node): '''Return the arguments from a Structure Constructor stored as a CodeBlock containing an fparser2 ast. :param code_block: the CodeBlock containing a StructureConstructor. :type code_block: :py:class:`psyclone.psyir.nodes.CodeBlock` :param fp2_node: the fparser2 Structure Constructor node. :type fp2_node: \ :py:class:`fparser.two.Fortran2003.Structure_Constructor` :returns: a list of PSyIR nodes containing the \ StructureConstructor arguments. :rtype: list of :py:class:`psyclone.psyir.nodes.Node` ''' dummy_call = Call(RoutineSymbol("dummy"), parent=code_block.parent) fparser2 = Fparser2Reader() for arg in fp2_node.children[1].children: fparser2.process_nodes(dummy_call, [arg]) return dummy_call.pop_all_children()
def test_call_error3(): '''Test that the appropriate exception is raised if one or more of the arguments argument list entries to the create method is not a DataNode. ''' routine = RoutineSymbol("roo") with pytest.raises(GenerationError) as info: _ = Call.create(routine, [Reference(DataSymbol("arg1", INTEGER_TYPE)), None]) assert ("Item 'NoneType' can't be child 1 of 'Call'. The valid format " "is: '[DataNode]*'." in str(info.value))
def test_invoke_error(): '''Test that the expected exception is raised in the validate method when the supplied node is a call but its name is not the expected 'invoke' name. ''' invoke_trans = InvokeCallTrans() with pytest.raises(TransformationError) as info: invoke_trans.validate(Call(RoutineSymbol("hello"))) assert ("Error in InvokeCallTrans transformation. The supplied call " "argument should be a `Call` node with name 'invoke' but " "found 'hello'." in str(info.value))
def test_call_create(): '''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)), Array(DataSymbol("arg2", array_type)) ] call = Call.create(routine, arguments) assert call.routine is routine for idx, child, in enumerate(call.children): assert child is arguments[idx] assert child.parent is call
"w3", interface=READ_ARG) for symbol in [NQP_XY, NQP_Z, WEIGHTS_XY, WEIGHTS_Z, BASIS_W3, DIFF_BASIS_W3]: SYMBOL_TABLE.add(symbol) SYMBOL_TABLE.specify_argument_list([ NDF_W3, UNDF_W3, NCELL_3D, FIELD2, OPERATOR, NQP_XY, NQP_Z, WEIGHTS_XY, WEIGHTS_Z, BASIS_W3, DIFF_BASIS_W3 ]) # Routine symbol ROUTINE_SYMBOL = RoutineSymbol("my_sub") # Call CALL = Call.create(ROUTINE_SYMBOL, [Reference(FIELD1), Reference(FIELD2), Reference(OPERATOR)]) # KernelSchedule KERNEL_SCHEDULE = KernelSchedule.create("work", SYMBOL_TABLE, [CALL]) # Container CONTAINER_SYMBOL_TABLE = SymbolTable() CONTAINER = Container.create("CONTAINER", CONTAINER_SYMBOL_TABLE, [KERNEL_SCHEDULE]) # Write out the code as Fortran WRITER = FortranWriter() RESULT = WRITER(CONTAINER) print(RESULT)
def test_call_str(): ''' Test that the str method behaves as expected ''' routine = RoutineSymbol("roo") call = Call(routine) assert str(call) == "Call[name='roo']"
def test_call_node_str(): ''' Test that the node_str method behaves as expected ''' routine = RoutineSymbol("isaac") call = Call(routine) colouredtext = colored("Call", SCHEDULE_COLOUR_MAP["Call"]) assert call.node_str() == colouredtext + "[name='isaac']"
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
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) ASSIGN6 = Assignment.create(TMPARRAY, TWO) # Call CALL = Call.create(ROUTINE_SYMBOL, [TMP1, BINARYOPERATION]) # 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, [CALL, ASSIGN2, LOOP, ASSIGN5, ASSIGN6]) # Container CONTAINER_SYMBOL_TABLE = SymbolTable() CONTAINER = Container.create("CONTAINER", CONTAINER_SYMBOL_TABLE,