def test_assignment_children_validation(): '''Test that children added to assignment are validated. Assignment accepts just 2 children and both are DataNodes. ''' # Create method with lhs not a Node. with pytest.raises(GenerationError) as excinfo: _ = Assignment.create("invalid", Literal("0.0", REAL_SINGLE_TYPE)) assert ("Item 'str' can't be child 0 of 'Assignment'. The valid format " "is: 'DataNode, DataNode'.") in str(excinfo.value) # Create method with rhs not a Node. with pytest.raises(GenerationError) as excinfo: _ = Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)), "invalid") assert ("Item 'str' can't be child 1 of 'Assignment'. The valid format " "is: 'DataNode, DataNode'.") in str(excinfo.value) # Direct assignment of a 3rd children assignment = Assignment.create( Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)), Literal("0.0", REAL_SINGLE_TYPE)) with pytest.raises(GenerationError) as excinfo: assignment.children.append(Literal("0.0", REAL_SINGLE_TYPE)) assert ("Item 'Literal' can't be child 2 of 'Assignment'. The valid format" " is: 'DataNode, DataNode'.") in str(excinfo.value)
def test_apply2(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 includes extra indices for the vector and matrix arrays with additional indices being literals. ''' trans = Matmul2CodeTrans() matmul = create_matmul() matmul.children[0].children[2] = Literal("1", INTEGER_TYPE) matmul.children[1].children[1] = Literal("2", INTEGER_TYPE) trans.apply(matmul) writer = FortranWriter() result = writer(matmul.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" " result(i) = 0.0\n" " do j = 1, 10, 1\n" " result(i) = result(i) + x(i,j,1) * y(j,2)\n" " enddo\n" " enddo\n" "\n" "end subroutine my_kern" in result) assert Compile(tmpdir).string_compiles(result)
def test_lower_to_lang_level_single_node(): ''' Test the lower_to_language_level() method when a Schedule contains a single ProfileNode. ''' Profiler.set_options([Profiler.INVOKES]) symbol_table = SymbolTable() arg1 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE) zero = Literal("0.0", REAL_TYPE) one = Literal("1.0", REAL_TYPE) assign1 = Assignment.create(Reference(arg1), zero) assign2 = Assignment.create(Reference(arg1), one) kschedule = KernelSchedule.create( "work1", symbol_table, [assign1, assign2, Return()]) Profiler.add_profile_nodes(kschedule, Loop) assert isinstance(kschedule.children[0], ProfileNode) assert isinstance(kschedule.children[-1], Return) kschedule.lower_to_language_level() # The ProfileNode should have been replaced by two CodeBlocks with its # children inserted between them. assert isinstance(kschedule[0], CodeBlock) # The first CodeBlock should have the "profile-start" annotation. assert kschedule[0].annotations == ["profile-start"] ptree = kschedule[0].get_ast_nodes assert len(ptree) == 1 assert isinstance(ptree[0], Fortran2003.Call_Stmt) assert kschedule[1] is assign1 assert kschedule[2] is assign2 assert isinstance(kschedule[-2], CodeBlock) assert kschedule[-2].annotations == [] ptree = kschedule[-2].get_ast_nodes assert len(ptree) == 1 assert isinstance(ptree[0], Fortran2003.Call_Stmt) assert isinstance(kschedule[-1], Return)
def test_range_view(capsys): ''' Check that calling view() on an array with a child Range works as expected. ''' from psyclone.psyir.nodes import Array from psyclone.psyir.nodes.node import colored, SCHEDULE_COLOUR_MAP # 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 = Array.create(DataSymbol("my_array", array_type), [Literal("1", INTEGER_SINGLE_TYPE), erange]) array.view() stdout, _ = capsys.readouterr() arrayref = colored("ArrayReference", SCHEDULE_COLOUR_MAP[array._colour_key]) literal = colored("Literal", SCHEDULE_COLOUR_MAP[array.children[0]._colour_key]) rangestr = colored("Range", SCHEDULE_COLOUR_MAP[erange._colour_key]) 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)
def test_create(): '''Test that the static create() method creates a NemoLoop instance and its children corectly. ''' variable = DataSymbol("ji", INTEGER_TYPE) start = Literal("2", INTEGER_TYPE) stop = Literal("10", INTEGER_TYPE) step = Literal("1", INTEGER_TYPE) x_var = DataSymbol("X", REAL_TYPE) children = [Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))] nemo_loop = NemoLoop.create(variable, start, stop, step, children) assert isinstance(nemo_loop, NemoLoop) assert nemo_loop.loop_type == "lon" assert isinstance(nemo_loop.loop_body, Schedule) assert len(nemo_loop.loop_body.children) == 1 assert nemo_loop.loop_body.children[0] is children[0] assert children[0].parent is nemo_loop.loop_body assert nemo_loop.loop_body.parent is nemo_loop assert nemo_loop.variable is variable assert nemo_loop.start_expr is start assert nemo_loop.stop_expr is stop assert nemo_loop.step_expr is step writer = FortranWriter() result = writer(nemo_loop) assert ("do ji = 2, 10, 1\n" " X = 3.0\n" "enddo" in result)
def test_scope(): '''Test that the scope method in a Node instance returns the closest ancestor Schedule or Container Node (including itself) or raises an exception if one does not exist. ''' kernel_symbol_table = SymbolTable() symbol = DataSymbol("tmp", REAL_TYPE) kernel_symbol_table.add(symbol) ref = Reference(symbol) assign = Assignment.create(ref, Literal("0.0", REAL_TYPE)) kernel_schedule = KernelSchedule.create("my_kernel", kernel_symbol_table, [assign]) container = Container.create("my_container", SymbolTable(), [kernel_schedule]) assert ref.scope is kernel_schedule assert assign.scope is kernel_schedule assert kernel_schedule.scope is kernel_schedule assert container.scope is container anode = Literal("x", INTEGER_TYPE) with pytest.raises(SymbolError) as excinfo: _ = anode.scope assert ("Unable to find the scope of node " "'Literal[value:'x', Scalar<INTEGER, UNDEFINED>]' as " "none of its ancestors are Container or Schedule nodes." in str(excinfo.value))
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 = Array(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"
def __init__(self, parent=None, loop_type=""): Loop.__init__(self, parent=parent, valid_loop_types=["", "colours", "colour"]) self.loop_type = loop_type # Work out the variable name from the loop type if self._loop_type == "colours": tag = "colours_loop_idx" suggested_name = "colour" elif self._loop_type == "colour": tag = "colour_loop_idx" suggested_name = "cell" else: tag = "cell_loop_idx" suggested_name = "cell" symtab = self.scope.symbol_table try: data_symbol = symtab.lookup_with_tag(tag) except KeyError: name = symtab.new_symbol_name(suggested_name) data_symbol = DataSymbol(name, INTEGER_TYPE) symtab.add(data_symbol, tag=tag) self.variable = data_symbol # Pre-initialise the Loop children # TODO: See issue #440 self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # start self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # stop self.addchild(Literal("1", INTEGER_TYPE, parent=self)) # step self.addchild(Schedule(parent=self)) # loop body
def test_create_errors(): '''Test that the expected exceptions are raised when the arguments to the create method are invalid. ''' variable = DataSymbol("ji", INTEGER_TYPE) start = Literal("2", INTEGER_TYPE) stop = Literal("10", INTEGER_TYPE) step = Literal("1", INTEGER_TYPE) x_var = DataSymbol("X", REAL_TYPE) children = [Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))] with pytest.raises(GenerationError) as info: _ = NemoLoop.create(None, start, stop, step, children) assert ("Generation Error: variable property in Loop class should be a " "DataSymbol but found 'NoneType'" in str(info.value)) with pytest.raises(GenerationError) as info: _ = NemoLoop.create(variable, None, stop, step, children) assert ("Generation Error: Item 'NoneType' can't be child 0 of 'Loop'. " "The valid format is: 'DataNode, DataNode, DataNode, Schedule'." in str(info.value)) with pytest.raises(GenerationError) as info: _ = NemoLoop.create(variable, start, None, step, children) assert ("Generation Error: Item 'NoneType' can't be child 1 of 'Loop'. " "The valid format is: 'DataNode, DataNode, DataNode, Schedule'." in str(info.value)) with pytest.raises(GenerationError) as info: _ = NemoLoop.create(variable, start, stop, None, children) assert ("Generation Error: Item 'NoneType' can't be child 2 of 'Loop'. " "The valid format is: 'DataNode, DataNode, DataNode, Schedule'." in str(info.value)) with pytest.raises(GenerationError) as info: _ = NemoLoop.create(variable, start, stop, step, None) assert ("Generation Error: children argument in create method of NemoLoop " "class should be a list but found 'NoneType'." in str(info.value))
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 = Array.create(array_symbol, [create_stepped_range(symbol_n)]) array_symbol = DataSymbol("z", ArrayType(REAL_TYPE, [10, 10])) symbol_table.add(array_symbol) array_z = Array.create( array_symbol, [Literal("1", INTEGER_TYPE), create_stepped_range(symbol_n)]) array_symbol = DataSymbol("a", ArrayType(REAL_TYPE, [10])) array_a = Array.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
def test_range_references_props(): ''' Test that the properties of a Range return what we expect when the start, stop and step are references or expressions. ''' from psyclone.psyir.nodes import BinaryOperation, KernelSchedule sched = KernelSchedule("test_sched") sym_table = sched.symbol_table start_symbol = DataSymbol("istart", INTEGER_SINGLE_TYPE) stop_symbol = DataSymbol("istop", INTEGER_SINGLE_TYPE) step_symbol = DataSymbol("istep", INTEGER_SINGLE_TYPE) sym_table.add(start_symbol) sym_table.add(stop_symbol) sym_table.add(step_symbol) startvar = Reference(start_symbol) stopvar = Reference(stop_symbol) start = BinaryOperation.create(BinaryOperation.Operator.SUB, startvar, Literal("1", INTEGER_SINGLE_TYPE)) stop = BinaryOperation.create(BinaryOperation.Operator.ADD, stopvar, Literal("1", INTEGER_SINGLE_TYPE)) step = Reference(step_symbol) erange = Range.create(start, stop, step) assert erange.start is start assert erange.stop is stop assert erange.step is step assert erange.children[0] is start assert erange.children[1] is stop assert erange.children[2] is step
def __init__(self, parent=None, topology_name="", loop_type=""): Loop.__init__(self, parent=parent, valid_loop_types=["inner", "outer"]) self.loop_type = loop_type if self._loop_type == "inner": tag = "inner_loop_idx" suggested_name = "i" elif self.loop_type == "outer": tag = "outer_loop_idx" suggested_name = "j" symtab = self.scope.symbol_table try: self.variable = symtab.lookup_with_tag(tag) except KeyError: self.variable = symtab.new_symbol(suggested_name, tag, symbol_type=DataSymbol, datatype=INTEGER_TYPE) # Pre-initialise the Loop children # TODO: See issue #440 self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # start self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # stop self.addchild(Literal("1", INTEGER_TYPE, parent=self)) # step self.addchild(Schedule(parent=self)) # loop body
def test_type_convert_binaryop_create(operation, op_str): '''Test that the create method in the BinaryOperation class correctly creates a BinaryOperation instance for the REAL and INT type-conversion operations.. ''' sym = DataSymbol("tmp1", REAL_SINGLE_TYPE) lhs = Reference(sym) wp_sym = DataSymbol("wp", INTEGER_SINGLE_TYPE) # Reference to a kind parameter rhs = Reference(wp_sym) binaryoperation = BinaryOperation.create(operation, lhs, rhs) assert binaryoperation._operator is operation check_links(binaryoperation, [lhs, rhs]) result = FortranWriter().binaryoperation_node(binaryoperation) assert op_str + "(tmp1, wp)" in result.lower() # Kind specified with an integer literal rhs = Literal("4", INTEGER_SINGLE_TYPE) binaryoperation = BinaryOperation.create(operation, lhs.detach(), rhs) check_links(binaryoperation, [lhs, rhs]) result = FortranWriter().binaryoperation_node(binaryoperation) assert op_str + "(tmp1, 4)" in result.lower() # Kind specified as an arithmetic expression rhs = BinaryOperation.create(BinaryOperation.Operator.ADD, Reference(wp_sym), Literal("2", INTEGER_SINGLE_TYPE)) binaryoperation = BinaryOperation.create(operation, lhs.detach(), rhs) check_links(binaryoperation, [lhs, rhs]) result = FortranWriter().binaryoperation_node(binaryoperation) assert op_str + "(tmp1, wp + 2)" in result.lower()
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.copy(), one.copy()) 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"
def test_arraytype(): '''Test that the ArrayType class __init__ works as expected. Test the different dimension datatypes that are supported.''' scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, 4) data_symbol = DataSymbol("var", scalar_type, constant_value=30) one = Literal("1", scalar_type) var_plus_1 = BinaryOperation.create(BinaryOperation.Operator.ADD, Reference(data_symbol), one) literal = Literal("20", scalar_type) array_type = ArrayType(scalar_type, [ 10, literal, var_plus_1, Reference(data_symbol), ArrayType.Extent.DEFERRED, ArrayType.Extent.ATTRIBUTE ]) assert isinstance(array_type, ArrayType) assert len(array_type.shape) == 6 # Provided as an int but stored as a Literal shape0 = array_type.shape[0] assert isinstance(shape0, Literal) assert shape0.value == "10" assert shape0.datatype.intrinsic == ScalarType.Intrinsic.INTEGER assert shape0.datatype.precision == ScalarType.Precision.UNDEFINED # Provided and stored as a Literal (DataNode) assert array_type.shape[1] is literal # Provided and stored as an Operator (DataNode) assert array_type.shape[2] is var_plus_1 # Provided and stored as a Reference to a DataSymbol assert isinstance(array_type.shape[3], Reference) assert array_type.shape[3].symbol is data_symbol # Provided and stored as a deferred extent assert array_type.shape[4] == ArrayType.Extent.DEFERRED # Provided as an attribute extent assert array_type.shape[5] == ArrayType.Extent.ATTRIBUTE
def test_binaryoperation_node_str(): ''' Check the node_str method of the Binary Operation class.''' binary_operation = BinaryOperation(BinaryOperation.Operator.ADD) op1 = Literal("1", INTEGER_SINGLE_TYPE) op2 = Literal("1", INTEGER_SINGLE_TYPE) binary_operation.addchild(op1) binary_operation.addchild(op2) coloredtext = colored("BinaryOperation", BinaryOperation._colour) assert coloredtext+"[operator:'ADD']" in binary_operation.node_str()
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)) nary_operation.addchild(Literal("1", INTEGER_SINGLE_TYPE)) nary_operation.addchild(Literal("1", INTEGER_SINGLE_TYPE)) coloredtext = colored("NaryOperation", NaryOperation._colour) assert coloredtext+"[operator:'MAX']" in nary_operation.node_str()
def test_literal_init_empty_value(): '''Test the initialisation of a Literal object with an empty value argument raises the expected exception unless it is of CHARACTER_TYPE. ''' with pytest.raises(ValueError) as err: Literal("", REAL_DOUBLE_TYPE) assert "A non-character literal value cannot be empty." in str(err.value) lit = Literal("", CHARACTER_TYPE) assert lit.value == ""
def test_binaryoperation_node_str(): ''' Check the node_str method of the Binary Operation class.''' from psyclone.psyir.nodes.node import colored, SCHEDULE_COLOUR_MAP binary_operation = BinaryOperation(BinaryOperation.Operator.ADD) op1 = Literal("1", INTEGER_SINGLE_TYPE, parent=binary_operation) op2 = Literal("1", INTEGER_SINGLE_TYPE, parent=binary_operation) binary_operation.addchild(op1) binary_operation.addchild(op2) coloredtext = colored("BinaryOperation", SCHEDULE_COLOUR_MAP["Operation"]) assert coloredtext + "[operator:'ADD']" in binary_operation.node_str()
def test_literal_children_validation(): '''Test that children added to Literals are validated. A Literal node does not accept any children. ''' literal = Literal("1", INTEGER_SINGLE_TYPE) with pytest.raises(GenerationError) as excinfo: literal.addchild(Literal("2", INTEGER_SINGLE_TYPE)) assert ("Item 'Literal' can't be child 0 of 'Literal'. Literal is a" " LeafNode and doesn't accept children.") in str(excinfo.value)
def test_correct_2abs(tmpdir): '''Check that a valid example produces the expected output when there is more than one ABS() in an expression. ''' Config.get().api = "nemo" operation = example_psyir( lambda arg: BinaryOperation.create( BinaryOperation.Operator.MUL, arg, Literal("3.14", REAL_TYPE))) root = operation.root assignment = operation.parent abs_op = UnaryOperation.create(UnaryOperation.Operator.ABS, Literal("1.0", REAL_TYPE)) operation.detach() op1 = BinaryOperation.create(BinaryOperation.Operator.ADD, operation, abs_op) assignment.addchild(op1) writer = FortranWriter() result = writer(root) assert ( "subroutine abs_example(arg)\n" " real, intent(inout) :: arg\n" " real :: psyir_tmp\n\n" " psyir_tmp = ABS(arg * 3.14) + ABS(1.0)\n\n" "end subroutine abs_example\n") in result trans = Abs2CodeTrans() trans.apply(operation, root.symbol_table) trans.apply(abs_op, root.symbol_table) result = writer(root) assert ( "subroutine abs_example(arg)\n" " real, intent(inout) :: arg\n" " real :: psyir_tmp\n" " real :: res_abs\n" " real :: tmp_abs\n" " real :: res_abs_1\n" " real :: tmp_abs_1\n\n" " tmp_abs = arg * 3.14\n" " if (tmp_abs > 0.0) then\n" " res_abs = tmp_abs\n" " else\n" " res_abs = tmp_abs * -1.0\n" " end if\n" " tmp_abs_1 = 1.0\n" " if (tmp_abs_1 > 0.0) then\n" " res_abs_1 = tmp_abs_1\n" " else\n" " res_abs_1 = tmp_abs_1 * -1.0\n" " end if\n" " psyir_tmp = res_abs + res_abs_1\n\n" "end subroutine abs_example\n") in result assert Compile(tmpdir).string_compiles(result) # Remove the created config instance Config._instance = None
def test_loop_navigation_properties(): # pylint: disable=too-many-statements ''' Tests the start_expr, stop_expr, step_expr and loop_body setter and getter properties. ''' loop = Loop() # Properties return an error if the node is incomplete error_str = ("Loop is incomplete. It should have exactly 4 " "children, but found") with pytest.raises(InternalError) as err: _ = loop.start_expr assert error_str in str(err.value) loop.addchild(Literal("start", INTEGER_SINGLE_TYPE)) loop.addchild(Literal("stop", INTEGER_SINGLE_TYPE)) loop.addchild(Literal("step", INTEGER_SINGLE_TYPE)) # If it's not fully complete, it still returns an error with pytest.raises(InternalError) as err: _ = loop.start_expr assert error_str in str(err.value) with pytest.raises(InternalError) as err: _ = loop.stop_expr assert error_str in str(err.value) with pytest.raises(InternalError) as err: _ = loop.step_expr assert error_str in str(err.value) with pytest.raises(InternalError) as err: _ = loop.loop_body assert error_str in str(err.value) with pytest.raises(InternalError) as err: loop.start_expr = Literal("invalid", INTEGER_SINGLE_TYPE) assert error_str in str(err.value) with pytest.raises(InternalError) as err: loop.stop_expr = Literal("invalid", INTEGER_SINGLE_TYPE) assert error_str in str(err.value) with pytest.raises(InternalError) as err: loop.step_expr = Literal("invalid", INTEGER_SINGLE_TYPE) assert error_str in str(err.value) # Check that Getters properties work loop.addchild(Schedule(parent=loop)) loop.loop_body.addchild(Return(parent=loop.loop_body)) assert loop.start_expr.value == "start" assert loop.stop_expr.value == "stop" assert loop.step_expr.value == "step" assert isinstance(loop.loop_body[0], Return) # Test Setters loop.start_expr = Literal("newstart", INTEGER_SINGLE_TYPE) loop.stop_expr = Literal("newstop", INTEGER_SINGLE_TYPE) loop.step_expr = Literal("newstep", INTEGER_SINGLE_TYPE) assert loop.start_expr.value == "newstart" assert loop.stop_expr.value == "newstop" assert loop.step_expr.value == "newstep"
def test_correct_2min(tmpdir): '''Check that a valid example produces the expected output when there is more than one MIN() in an expression. ''' Config.get().api = "nemo" operation = example_psyir_binary(lambda arg: arg) root = operation.root assignment = operation.parent operation.detach() min_op = BinaryOperation.create(BinaryOperation.Operator.MIN, Literal("1.0", REAL_TYPE), Literal("2.0", REAL_TYPE)) op1 = BinaryOperation.create(BinaryOperation.Operator.ADD, min_op, operation) assignment.addchild(op1) writer = FortranWriter() result = writer(root) assert ("subroutine min_example(arg, arg_1)\n" " real, intent(inout) :: arg\n" " real, intent(inout) :: arg_1\n" " real :: psyir_tmp\n\n" " psyir_tmp = MIN(1.0, 2.0) + MIN(arg, arg_1)\n\n" "end subroutine min_example\n") in result trans = Min2CodeTrans() trans.apply(operation, root.symbol_table) trans.apply(min_op, root.symbol_table) result = writer(root) assert ("subroutine min_example(arg, arg_1)\n" " real, intent(inout) :: arg\n" " real, intent(inout) :: arg_1\n" " real :: psyir_tmp\n" " real :: res_min\n" " real :: tmp_min\n" " real :: res_min_1\n" " real :: tmp_min_1\n\n" " res_min = arg\n" " tmp_min = arg_1\n" " if (tmp_min < res_min) then\n" " res_min = tmp_min\n" " end if\n" " res_min_1 = 1.0\n" " tmp_min_1 = 2.0\n" " if (tmp_min_1 < res_min_1) then\n" " res_min_1 = tmp_min_1\n" " end if\n" " psyir_tmp = res_min_1 + res_min\n\n" "end subroutine min_example\n") in result assert Compile(tmpdir).string_compiles(result) # Remove the created config instance Config._instance = None
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_create_unknown(): '''Test that the static create() method creates a NemoLoop instance with an unknown loop type if the loop type is not recognised. ''' variable = DataSymbol("idx", INTEGER_TYPE) start = Literal("2", INTEGER_TYPE) stop = Literal("10", INTEGER_TYPE) step = Literal("1", INTEGER_TYPE) x_var = DataSymbol("X", REAL_TYPE) children = [Assignment.create(Reference(x_var), Literal("3.0", REAL_TYPE))] nemo_loop = NemoLoop.create(variable, start, stop, step, children) assert nemo_loop.loop_type == "unknown"
def test_correct_expr(tmpdir): '''Check that a valid example produces the expected output when SIGN is part of an expression. ''' Config.get().api = "nemo" operation = example_psyir(lambda arg: BinaryOperation.create( BinaryOperation.Operator.MUL, arg, Literal("3.14", REAL_TYPE))) root = operation.root assignment = operation.parent operation.detach() op1 = BinaryOperation.create(BinaryOperation.Operator.ADD, Literal("1.0", REAL_TYPE), operation) op2 = BinaryOperation.create(BinaryOperation.Operator.ADD, op1, Literal("2.0", REAL_TYPE)) assignment.addchild(op2) writer = FortranWriter() result = writer(root) assert ("subroutine sign_example(arg, arg_1)\n" " real, intent(inout) :: arg\n" " real, intent(inout) :: arg_1\n" " real :: psyir_tmp\n\n" " psyir_tmp = 1.0 + SIGN(arg * 3.14, arg_1) + 2.0\n\n" "end subroutine sign_example\n") in result trans = Sign2CodeTrans() trans.apply(operation, root.symbol_table) result = writer(root) assert ("subroutine sign_example(arg, arg_1)\n" " real, intent(inout) :: arg\n" " real, intent(inout) :: arg_1\n" " real :: psyir_tmp\n" " real :: res_sign\n" " real :: tmp_sign\n" " real :: res_abs\n" " real :: tmp_abs\n\n" " tmp_abs = arg * 3.14\n" " if (tmp_abs > 0.0) then\n" " res_abs = tmp_abs\n" " else\n" " res_abs = tmp_abs * -1.0\n" " end if\n" " res_sign = res_abs\n" " tmp_sign = arg_1\n" " if (tmp_sign < 0.0) then\n" " res_sign = res_sign * -1.0\n" " end if\n" " psyir_tmp = 1.0 + res_sign + 2.0\n\n" "end subroutine sign_example\n") in result assert Compile(tmpdir).string_compiles(result) # Remove the created config instance Config._instance = None
def test_binaryoperation_can_be_printed(): '''Test that a Binary Operation instance can always be printed (i.e. is initialised fully)''' binary_operation = BinaryOperation(BinaryOperation.Operator.ADD) assert "BinaryOperation[operator:'ADD']" in str(binary_operation) op1 = Literal("1", INTEGER_SINGLE_TYPE) op2 = Literal("2", INTEGER_SINGLE_TYPE) binary_operation.addchild(op1) binary_operation.addchild(op2) # Check the node children are also printed assert ("Literal[value:'1', Scalar<INTEGER, SINGLE>]\n" in str(binary_operation)) assert ("Literal[value:'2', Scalar<INTEGER, SINGLE>]" in str(binary_operation))
def test_loop_create_invalid(): '''Test that the create method in a Loop class raises the expected exception if the provided input is invalid. ''' zero = Literal("0", INTEGER_SINGLE_TYPE) one = Literal("1", INTEGER_SINGLE_TYPE) children = [ Assignment.create(Reference(DataSymbol("x", INTEGER_SINGLE_TYPE)), one) ] # invalid variable (test_check_variable tests check all ways a # variable could be invalid. Here we just check that the # _check_variable() method is called correctly) with pytest.raises(GenerationError) as excinfo: _ = Loop.create(1, zero, one, one, children) assert ("variable property in Loop class should be a DataSymbol but " "found 'int'.") in str(excinfo.value) variable = DataSymbol("i", INTEGER_TYPE) # start not a Node. with pytest.raises(GenerationError) as excinfo: _ = Loop.create(variable, "invalid", one, one, children) assert ("Item 'str' can't be child 0 of 'Loop'. The valid format is: " "'DataNode, DataNode, DataNode, Schedule'.") in str(excinfo.value) # stop not a Node. with pytest.raises(GenerationError) as excinfo: _ = Loop.create(variable, zero, "invalid", one, children) assert ("Item 'str' can't be child 1 of 'Loop'. The valid format is: " "'DataNode, DataNode, DataNode, Schedule'.") in str(excinfo.value) # step not a Node. with pytest.raises(GenerationError) as excinfo: _ = Loop.create(variable, zero, one, "invalid", children) assert ("Item 'str' can't be child 2 of 'Loop'. The valid format is: " "'DataNode, DataNode, DataNode, Schedule'.") in str(excinfo.value) # children not a list with pytest.raises(GenerationError) as excinfo: _ = Loop.create(variable, zero, one, one, "invalid") assert ("children argument in create method of Loop class should " "be a list but found 'str'." in str(excinfo.value)) # contents of children list are not Node. with pytest.raises(GenerationError) as excinfo: _ = Loop.create(variable, zero, one, one, ["invalid"]) assert ("Item 'str' can't be child 0 of 'Schedule'. The valid format is: " "'[Statement]*'." in str(excinfo.value))
def test_cw_literal(): '''Check the CWriter class literal method correctly prints out the C representation of a Literal. ''' cwriter = CWriter() lit = Literal('1', INTEGER_TYPE) assert cwriter(lit) == '1' # Test that scientific notation is output correctly lit = Literal("3e5", REAL_TYPE, None) assert cwriter(lit) == '3e5'
def test_ifblock_create_invalid(): '''Test that the create method in an IfBlock class raises the expected exception if the provided input is invalid. ''' if_condition = Literal('true', BOOLEAN_TYPE) if_body = [ Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)), Literal("0.0", REAL_SINGLE_TYPE)), Assignment.create(Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)), Literal("1.0", REAL_SINGLE_TYPE)) ] # if_condition not a Node. with pytest.raises(GenerationError) as excinfo: _ = IfBlock.create("True", if_body) assert ("Item 'str' can't be child 0 of 'If'. The valid format is: " "'DataNode, Schedule [, Schedule]'.") in str(excinfo.value) # One or more if body not a Node. if_body_err = [ Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)), Literal("0.0", REAL_SINGLE_TYPE)), "invalid" ] with pytest.raises(GenerationError) as excinfo: _ = IfBlock.create(if_condition, if_body_err) assert ("Item 'str' can't be child 1 of 'Schedule'. The valid format is: " "'[Statement]*'.") in str(excinfo.value) # If body not a list. with pytest.raises(GenerationError) as excinfo: _ = IfBlock.create(if_condition, "invalid") assert ("if_body argument in create method of IfBlock class should be a " "list.") in str(excinfo.value) # One of more of else_body not a Node. else_body_err = [ Assignment.create(Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)), Literal("1.0", REAL_SINGLE_TYPE)), "invalid" ] with pytest.raises(GenerationError) as excinfo: _ = IfBlock.create(if_condition, if_body, else_body_err) assert ("Item 'str' can't be child 1 of 'Schedule'. The valid format is: " "'[Statement]*'.") in str(excinfo.value) # Else body not a list. with pytest.raises(GenerationError) as excinfo: _ = IfBlock.create(if_condition, if_body, "invalid") assert ("else_body argument in create method of IfBlock class should be a " "list.") in str(excinfo.value)