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 = ArrayReference.create(array_symbol, [create_stepped_range(symbol_n)]) array_symbol = DataSymbol("z", ArrayType(REAL_TYPE, [10, 10])) symbol_table.add(array_symbol) array_z = ArrayReference.create( array_symbol, [Literal("1", INTEGER_TYPE), create_stepped_range(symbol_n)]) array_symbol = DataSymbol("a", ArrayType(REAL_TYPE, [10])) array_a = ArrayReference.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_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 and false otherwise. ''' one = Literal("1.0", REAL_TYPE) int_one = Literal("1", INTEGER_TYPE) var = DataSymbol("x", REAL_TYPE) reference = Reference(var) # lhs is not an array assignment = Assignment.create(reference, one) assert not assignment.is_array_range # lhs is an array reference but has no range array_type = ArrayType(REAL_TYPE, [10, 10]) symbol = DataSymbol("x", array_type) array_ref = ArrayReference(symbol, [1, 3]) assignment = Assignment.create(array_ref, one) assert not assignment.is_array_range # lhs is an array reference with a range my_range = Range.create(int_one, int_one, int_one) array_ref = ArrayReference.create(symbol, [my_range, int_one]) assignment = Assignment.create(array_ref, one) assert assignment.is_array_range
def test_array_range_with_reduction(): ''' Test that we correctly identify an array range when it is the result of a reduction from an array, e.g x(1, INT(SUM(map(:, :), 1))) = 1.0 ''' one = Literal("1.0", REAL_TYPE) int_one = Literal("1", INTEGER_TYPE) int_two = Literal("2", INTEGER_TYPE) int_array_type = ArrayType(INTEGER_SINGLE_TYPE, [10, 10]) map_sym = DataSymbol("map", int_array_type) array_type = ArrayType(REAL_TYPE, [10, 10]) symbol = DataSymbol("x", 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) lbound2 = BinaryOperation.create(BinaryOperation.Operator.LBOUND, Reference(map_sym), int_two.copy()) ubound2 = BinaryOperation.create(BinaryOperation.Operator.UBOUND, Reference(map_sym), int_two.copy()) my_range2 = Range.create(lbound2, ubound2) bsum_op = BinaryOperation.create( BinaryOperation.Operator.SUM, ArrayReference.create(map_sym, [my_range1, my_range2]), int_one.copy()) int_op2 = UnaryOperation.create(UnaryOperation.Operator.INT, bsum_op) assignment = Assignment.create( ArrayReference.create(symbol, [int_one.copy(), int_op2]), one.copy()) assert assignment.is_array_range is True
def test_is_not_array_range(): ''' Test that is_array_range correctly rejects things that aren't an assignment to an array range. ''' int_one = Literal("1", INTEGER_SINGLE_TYPE) one = Literal("1.0", REAL_TYPE) var = DataSymbol("x", REAL_TYPE) reference = Reference(var) # lhs is not an array assignment = Assignment.create(reference, one) assert assignment.is_array_range is False # lhs is an array reference but has no range array_type = ArrayType(REAL_TYPE, [10, 10]) symbol = DataSymbol("y", array_type) array_ref = Reference(symbol) assignment = Assignment.create(array_ref, one.copy()) assert assignment.is_array_range is False # lhs is an array reference but the single index value is obtained # using an array range, y(1, SUM(map(:), 1)) = 1.0 int_array_type = ArrayType(INTEGER_SINGLE_TYPE, [10]) map_sym = DataSymbol("map", int_array_type) start = BinaryOperation.create(BinaryOperation.Operator.LBOUND, Reference(map_sym), int_one.copy()) stop = BinaryOperation.create(BinaryOperation.Operator.UBOUND, Reference(map_sym), int_one.copy()) my_range = Range.create(start, stop) sum_op = BinaryOperation.create(BinaryOperation.Operator.SUM, ArrayReference.create(map_sym, [my_range]), int_one.copy()) assignment = Assignment.create( ArrayReference.create(symbol, [int_one.copy(), sum_op]), one.copy()) assert assignment.is_array_range is False # When the slice has two operator ancestors, one of which is a reduction # e.g y(1, SUM(ABS(map(:)), 1)) = 1.0 abs_op = UnaryOperation.create( UnaryOperation.Operator.ABS, ArrayReference.create(map_sym, [my_range.copy()])) sum_op2 = BinaryOperation.create(BinaryOperation.Operator.SUM, abs_op, int_one.copy()) assignment = Assignment.create( ArrayReference.create(symbol, [int_one.copy(), sum_op2]), one.copy()) assert assignment.is_array_range is False # lhs is a scalar member of a structure 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) grid_sym = DataSymbol("grid", grid_type_symbol) assignment = Assignment.create(StructureReference.create(grid_sym, ["dx"]), one.copy()) assert assignment.is_array_range is False
def test_array_node_str(): ''' Check the node_str method of the ArrayReference class.''' kschedule = KernelSchedule("kname") array_type = ArrayType(INTEGER_SINGLE_TYPE, [ArrayType.Extent.ATTRIBUTE]) symbol = DataSymbol("aname", array_type) kschedule.symbol_table.add(symbol) array = ArrayReference(symbol) coloredtext = colored("ArrayReference", ArrayReference._colour) assert coloredtext + "[name:'aname']" in array.node_str()
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 = ArrayReference(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 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, one) 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_validate_intrinsic(): '''Check that the validate method returns an exception if the rhs of the assignment contains an operator that only returns an array i.e. can't be performed elementwise. At the moment MATMUL is the only operator of this type. ''' symbol_table = SymbolTable() array_x = create_array_x(symbol_table) array_y_2 = create_array_y_2d_slice(symbol_table) matmul = BinaryOperation.create(BinaryOperation.Operator.MATMUL, array_y_2, array_x) reference = ArrayReference.create( symbol_table.lookup("x"), [create_range(symbol_table.lookup("x"), 1)]) assignment = Assignment.create(reference, matmul) trans = ArrayRange2LoopTrans() with pytest.raises(TransformationError) as info: trans.validate(assignment) assert ("Error in ArrayRange2LoopTrans transformation. The rhs of the " "supplied Assignment node 'BinaryOperation[operator:'MATMUL']\n" "ArrayReference[name:'y2']\nRange[]\nRange[]\n\n" "ArrayReference[name:'x']\nRange[]\n' contains the " "MATMUL operator which can't be performed elementwise." in str(info.value))
def test_array_create_invalid3(): '''Test that the create method in an ArrayReference class raises the expected exception if the provided input is invalid. ''' # symbol argument is not a DataSymbol with pytest.raises(GenerationError) as excinfo: _ = ArrayReference.create([], []) assert ("symbol argument in create method of ArrayReference class should " "be a DataSymbol but found 'list'." in str(excinfo.value)) # children not a list with pytest.raises(GenerationError) as excinfo: _ = ArrayReference.create(DataSymbol("temp", REAL_SINGLE_TYPE), "invalid") assert ("indices argument in create method of ArrayReference class should" " be a list but found 'str'." in str(excinfo.value))
def create_matmul(): '''Utility function that creates a valid matmul node for use with subsequent tests. ''' symbol_table = SymbolTable() one = Literal("1", INTEGER_TYPE) two = Literal("2", INTEGER_TYPE) index = DataSymbol("idx", INTEGER_TYPE, constant_value=3) symbol_table.add(index) array_type = ArrayType(REAL_TYPE, [5, 10, 15]) mat_symbol = DataSymbol("x", array_type) symbol_table.add(mat_symbol) lbound1 = BinaryOperation.create(BinaryOperation.Operator.LBOUND, Reference(mat_symbol), one.copy()) ubound1 = BinaryOperation.create(BinaryOperation.Operator.UBOUND, Reference(mat_symbol), one.copy()) my_mat_range1 = Range.create(lbound1, ubound1, one.copy()) lbound2 = BinaryOperation.create(BinaryOperation.Operator.LBOUND, Reference(mat_symbol), two.copy()) ubound2 = BinaryOperation.create(BinaryOperation.Operator.UBOUND, Reference(mat_symbol), two.copy()) my_mat_range2 = Range.create(lbound2, ubound2, one.copy()) matrix = ArrayReference.create( mat_symbol, [my_mat_range1, my_mat_range2, Reference(index)]) array_type = ArrayType(REAL_TYPE, [10, 20]) vec_symbol = DataSymbol("y", array_type) symbol_table.add(vec_symbol) lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND, Reference(vec_symbol), one.copy()) ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND, Reference(vec_symbol), one.copy()) my_vec_range = Range.create(lbound, ubound, one.copy()) vector = ArrayReference.create( vec_symbol, [my_vec_range, Reference(index)]) matmul = BinaryOperation.create(BinaryOperation.Operator.MATMUL, matrix, vector) lhs_type = ArrayType(REAL_TYPE, [10]) lhs_symbol = DataSymbol("result", lhs_type) symbol_table.add(lhs_symbol) lhs = Reference(lhs_symbol) assign = Assignment.create(lhs, matmul) KernelSchedule.create("my_kern", symbol_table, [assign]) return matmul
def test_array_can_be_printed(): '''Test that an ArrayReference instance can always be printed (i.e. is initialised fully)''' kschedule = KernelSchedule("kname") symbol = DataSymbol("aname", INTEGER_SINGLE_TYPE) kschedule.symbol_table.add(symbol) assignment = Assignment() array = ArrayReference(symbol, assignment) assert "ArrayReference[name:'aname']\n" in str(array)
def test_array_is_lower_bound(): '''Test that the is_lower_bound method in the Array Node works as expected. ''' one = Literal("1", INTEGER_TYPE) array = ArrayReference.create(DataSymbol("test", ArrayType(REAL_TYPE, [10])), [one]) with pytest.raises(TypeError) as info: array.is_lower_bound("hello") assert ("The index argument should be an integer but found 'str'." in str(info.value)) # not a range node at index 0 assert not array.is_lower_bound(0) # range node does not have a binary operator for its start value array.children[0] = Range.create(one, one, one) assert not array.is_lower_bound(0) # range node lbound references a different array array2 = ArrayReference.create(DataSymbol("test2", ArrayType(REAL_TYPE, [10])), [one]) operator = BinaryOperation.create( BinaryOperation.Operator.LBOUND, array2, Literal("1", INTEGER_TYPE)) array.children[0] = Range.create(operator, one, one) assert not array.is_lower_bound(0) # range node lbound references a different index operator = BinaryOperation.create( BinaryOperation.Operator.LBOUND, array, Literal("2", INTEGER_TYPE)) array.children[0] = Range.create(operator, one, one) assert not array.is_lower_bound(0) # all is well operator = BinaryOperation.create( BinaryOperation.Operator.LBOUND, array, one) array.children[0] = Range.create(operator, one, one) assert array.is_lower_bound(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 = ArrayReference(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 = ArrayReference.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))
def test_array_create_invalid1(): '''Test that the create method in the ArrayReference class raises an exception if the provided symbol is not an array. ''' symbol_i = DataSymbol("i", INTEGER_SINGLE_TYPE) symbol_j = DataSymbol("j", INTEGER_SINGLE_TYPE) symbol_temp = DataSymbol("temp", REAL_SINGLE_TYPE) children = [Reference(symbol_i), Reference(symbol_j), Literal("1", INTEGER_SINGLE_TYPE)] with pytest.raises(GenerationError) as excinfo: _ = ArrayReference.create(symbol_temp, children) assert ("expecting the symbol to be an array, not a scalar." in str(excinfo.value))
def test_validate(): '''Test that the validate method in the ArrayRange2LoopTrans class raises the expected exceptions. ''' trans = ArrayRange2LoopTrans() with pytest.raises(TransformationError) as info: trans.validate(Node()) assert ( "Error in ArrayRange2LoopTrans transformation. The supplied node " "argument should be a PSyIR Assignment, but found 'Node'." in str(info.value)) with pytest.raises(TransformationError) as info: trans.validate(Assignment.create(DataNode(), DataNode())) assert ( "Error in ArrayRange2LoopTrans transformation. The lhs of the " "supplied Assignment node should be a PSyIR ArrayReference, but found " "'DataNode'." in str(info.value)) array_symbol = DataSymbol("x", ArrayType(INTEGER_TYPE, [10, 10])) one = Literal("1", INTEGER_TYPE) array_assignment = ArrayReference.create(array_symbol, [one, one.copy()]) with pytest.raises(TransformationError) as info: trans.validate(Assignment.create(array_assignment, DataNode())) assert ( "Error in ArrayRange2LoopTrans transformation. The lhs of the " "supplied Assignment node should be a PSyIR ArrayReference with at " "least one " "of its dimensions being a Range, but found None in " "'ArrayReference[name:'x']\\nLiteral[value:'1', " "Scalar<INTEGER, UNDEFINED>]\\nLiteral[value:'1', Scalar<INTEGER, " "UNDEFINED>]\\n'." in str(info.value)) array_x = create_array_x(SymbolTable()) assignment = Assignment.create( create_array_x(SymbolTable()), array_x) trans.validate(assignment) array_x.children[0].step = Literal("2", INTEGER_TYPE) with pytest.raises(TransformationError) as info: trans.validate(assignment) assert ( "The ArrayRange2LoopTrans transformation only supports ranges that " "are known to be the same as each other but array access 'x' " "dimension 0 and 'x' dimension 0 are either different or can't be " "determined in the assignment 'Assignment[]\\n" "ArrayReference[name:'x']\\nRange[]\\n" "ArrayReference[name:'x']\\nRange[]\\n'." in str(info.value))
def test_cw_size(): ''' Check the CWriter class SIZE method raises the expected error since there is no C equivalent. ''' cwriter = CWriter() arr = ArrayReference(DataSymbol('a', INTEGER_TYPE)) lit = Literal('1', INTEGER_TYPE) size = BinaryOperation.create(BinaryOperation.Operator.SIZE, arr, lit) lhs = Reference(DataSymbol('length', INTEGER_TYPE)) assignment = Assignment.create(lhs, size) with pytest.raises(VisitorError) as excinfo: cwriter(assignment) assert ("C backend does not support the 'Operator.SIZE' operator" in str(excinfo.value))
def test_array_create(): '''Test that the create method in the ArrayReference class correctly creates an ArrayReference instance. ''' array_type = ArrayType(REAL_SINGLE_TYPE, [10, 10, 10]) symbol_temp = DataSymbol("temp", array_type) symbol_i = DataSymbol("i", INTEGER_SINGLE_TYPE) symbol_j = DataSymbol("j", INTEGER_SINGLE_TYPE) children = [Reference(symbol_i), Reference(symbol_j), Literal("1", INTEGER_SINGLE_TYPE)] array = ArrayReference.create(symbol_temp, children) check_links(array, children) result = FortranWriter().arrayreference_node(array) assert result == "temp(i,j,1)"
def test_call_create(cls): '''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)), ArrayReference(DataSymbol("arg2", array_type)) ] call = cls.create(routine, arguments) # pylint: disable=unidiomatic-typecheck assert type(call) is cls assert call.routine is routine for idx, child, in enumerate(call.children): assert child is arguments[idx] assert child.parent is call
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 = ArrayReference(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)
def test_array_validate_index(): '''Test that the validate_index utility function behaves as expected.''' array = ArrayReference.create( DataSymbol("test", ArrayType(REAL_TYPE, [10])), [Literal("1", INTEGER_TYPE)]) with pytest.raises(TypeError) as info: array._validate_index("hello") assert ("The index argument should be an integer but found 'str'." in str(info.value)) with pytest.raises(ValueError) as info: array._validate_index(1) assert ("In ArrayReference 'test' the specified index '1' must be less " "than the number of dimensions '1'." in str(info.value)) array._validate_index(0) array._validate_index(-1)
def test_array_create_invalid2(): '''Test that the create method in the ArrayReference class raises an exception if the number of dimension in the provided symbol is different to the number of indices provided to the create method. ''' array_type = ArrayType(REAL_SINGLE_TYPE, [10]) symbol_temp = DataSymbol("temp", array_type) symbol_i = DataSymbol("i", INTEGER_SINGLE_TYPE) symbol_j = DataSymbol("j", INTEGER_SINGLE_TYPE) children = [Reference(symbol_i), Reference(symbol_j), Literal("1", INTEGER_SINGLE_TYPE)] with pytest.raises(GenerationError) as excinfo: _ = ArrayReference.create(symbol_temp, children) assert ("the symbol should have the same number of dimensions as indices " "(provided in the 'indices' argument). Expecting '3' but found " "'1'." in str(excinfo.value))
def test_reference(): '''Test that the common reference visitor writes the referenced symbol name or raises an error if the node is not Leaf node reference. ''' # Generate PSyIR Reference test_visitor = PSyIRVisitor() reference = Reference(DataSymbol('a', REAL_TYPE)) result = test_visitor(reference) assert result == "a" # Generate PSyIR ArrayReference reference2 = ArrayReference.create( DataSymbol('b', ArrayType(REAL_TYPE, shape=[1])), [reference]) with pytest.raises(VisitorError) as err: result = test_visitor(reference2) assert "Expecting a Reference with no children but found: " \ in str(err.value)
def create_array_x(symbol_table): '''Utility routine that creates and returns an array reference to a one-dimensional array "x". The array reference accesses all of the elements in the array dimension using a range node. In Fortran array notation this is "x(:)". :param symbol_table: the symbol table to which we add the array \ symbol. :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable` :returns: an array reference that accesses all elements of the \ array "x". :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference` ''' array_symbol = DataSymbol("x", ArrayType(REAL_TYPE, [10])) symbol_table.add(array_symbol) return ArrayReference.create(array_symbol, [create_range(array_symbol, 1)])
def create_array_y_2d_slice(symbol_table): '''Utility routine that creates and returns an array reference to a 2 dimensional array "y". The array reference accesses all elements in the 1st and 2nd dimensions of the array using range nodes. In Fortran array notation this is "y(:,:)". :param symbol_table: the symbol table to which we add the array \ symbol. :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable` :returns: an array reference that accesses all elements of the 1st \ and 2nd dimensions of the "y" array. :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference` ''' array_symbol = DataSymbol("y2", ArrayType(REAL_TYPE, [20, 10])) symbol_table.add(array_symbol) return ArrayReference.create(array_symbol, [create_range(array_symbol, 1), create_range(array_symbol, 2)])
def test_array_indices(): ''' Tests for the indices property (provided by the ArrayMixin class). ''' one = Literal("1", INTEGER_TYPE) array = ArrayReference.create( DataSymbol("test", ArrayType(REAL_TYPE, [10])), [one]) assert array.indices == [one] # Add an invalid child array._children = [one.copy(), "hello"] with pytest.raises(InternalError) as err: _ = array.indices assert ("ArrayReference malformed or incomplete: child 1 must by a " "psyir.nodes.DataNode or Range representing an array-index " "expression but found 'str'" in str(err.value)) # Remove the children altogether array._children = [] with pytest.raises(InternalError) as err: _ = array.indices assert ("ArrayReference malformed or incomplete: must have one or more " "children representing array-index expressions but found none" in str(err.value))
def test_validate5(): '''Check that the Matmul2Code validate method raises the expected exception when the supplied node is a MATMUL binary operation but either or both arguments are not references. ''' trans = Matmul2CodeTrans() array_type = ArrayType(REAL_TYPE, [10]) array = ArrayReference.create(DataSymbol("x", array_type), [Literal("10", INTEGER_TYPE)]) mult = BinaryOperation.create( BinaryOperation.Operator.MUL, array, array) matmul = BinaryOperation.create( BinaryOperation.Operator.MATMUL, mult, mult) _ = Assignment.create(array, matmul) with pytest.raises(TransformationError) as excinfo: trans.validate(matmul) assert ("Expected children of a MATMUL BinaryOperation to be references, " "but found 'BinaryOperation', 'BinaryOperation'." in str(excinfo.value))
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)
def gen_code(self, parent): ''' Work out the appropriate loop bounds and then call the base class to generate the code ''' self.start_expr = Literal("1", INTEGER_TYPE, parent=self) if self._loop_type == "colours": self.stop_expr = Reference(DataSymbol("ncolour", INTEGER_TYPE), parent=self) elif self._loop_type == "colour": self.stop_expr = ArrayReference(DataSymbol("ncp_ncolour", INTEGER_TYPE), parent=self) self.stop_expr.addchild(Reference( DataSymbol("colour", INTEGER_TYPE)), parent=self.stop_expr) else: # This is a hack as the name is not a valid DataSymbol, it # is a call to a type-bound function. self.stop_expr = Reference(DataSymbol( self.field_name + "%get_ncell()", INTEGER_TYPE), parent=self) Loop.gen_code(self, parent)
def create_array_y(symbol_table): '''Utility routine that creates and returns an array reference to a two-dimensional array "y". The array reference accesses all elements in the 2nd dimension of the array using a range node and the n'th element of the 1st dimension. In Fortran array notation this is "y(n,:)". :param symbol_table: the symbol table to which we add the array \ symbol and access the symbol "n". :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable` :returns: an array reference that accesses all elements of the \ 2nd dimension of array "y" and the n'th element of its 1st \ dimension. :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference` ''' array_symbol = DataSymbol("y", ArrayType(REAL_TYPE, [10, 10])) symbol_table.add(array_symbol) return ArrayReference.create(array_symbol, [Reference(symbol_table.lookup("n")), create_range(array_symbol, 2)])
def create_array_y_slice_subset(symbol_table): '''Utility routine that creates and returns an array reference to a 2 dimensional array "y". The array reference accesses elements 2 to "n" step 2 in the arrays 2nd dimension using a range node and the n'th element of the 1st dimension. In Fortran array notation this is "y(n,2:n:2)". :param symbol_table: the symbol table to which we add the array \ symbol and access the symbol "n". :type symbol_table: :py:class:`psyclone.psyir.symbol.SymbolTable` :returns: an array reference that accesses elements 2 to "n" step \ 2 in the array "y"'s 2nd dimension and the n'th element of its \ 1st dimension. :rtype: :py:class:`psyclone.psyir.nodes.ArrayReference` ''' array_symbol = DataSymbol("y3", ArrayType(REAL_TYPE, [10, 10])) symbol_table.add(array_symbol) symbol_n = symbol_table.lookup("n") return ArrayReference.create( array_symbol, [Reference(symbol_n), create_stepped_range(symbol_n)])