def test_oclw_gen_declaration(): '''Check the OpenCLWriter class gen_declaration method produces the expected declarations. ''' oclwriter = OpenCLWriter() # Basic entry - Scalar are passed by value and don't have additional # qualifiers. symbol = DataSymbol("dummy1", INTEGER_TYPE) result = oclwriter.gen_declaration(symbol) assert result == "int dummy1" # Array argument has a memory qualifier (only __global for now) array_type = ArrayType(INTEGER_TYPE, [2, ArrayType.Extent.ATTRIBUTE, 2]) symbol = DataSymbol("dummy2", array_type) result = oclwriter.gen_declaration(symbol) assert result == "__global int * restrict dummy2" # Array with unknown intent array_type = ArrayType(INTEGER_TYPE, [2, ArrayType.Extent.ATTRIBUTE, 2]) symbol = DataSymbol("dummy2", array_type, interface=ArgumentInterface( ArgumentInterface.Access.UNKNOWN)) result = oclwriter.gen_declaration(symbol) assert result == "__global int * restrict dummy2"
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_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_arraytype_immutable(): '''Test that the scalartype attributes can't be modified''' scalar_type = ScalarType(ScalarType.Intrinsic.REAL, 4) data_type = ArrayType(scalar_type, [10, 10]) with pytest.raises(AttributeError): data_type.intrinsic = ScalarType.Intrinsic.INTEGER with pytest.raises(AttributeError): data_type.precision = 8 with pytest.raises(AttributeError): data_type.shape = []
def test_datasymbol_copy(): '''Test that the DataSymbol copy method produces a faithful separate copy of the original symbol. ''' array_type = ArrayType(REAL_SINGLE_TYPE, [1, 2]) symbol = DataSymbol("myname", array_type, constant_value=None, interface=ArgumentInterface( ArgumentInterface.Access.READWRITE)) new_symbol = symbol.copy() # Check the new symbol has the same properties as the original assert symbol.name == new_symbol.name assert symbol.datatype == new_symbol.datatype assert symbol.shape == new_symbol.shape assert symbol.constant_value == new_symbol.constant_value assert symbol.interface == new_symbol.interface # Change the properties of the new symbol and check the original # is not affected. Can't check constant_value yet as we have a # shape value new_symbol._name = "new" new_symbol.datatype = ArrayType( ScalarType(ScalarType.Intrinsic.INTEGER, ScalarType.Precision.DOUBLE), [3, 4]) new_symbol._interface = LocalInterface() assert symbol.name == "myname" assert symbol.datatype.intrinsic == ScalarType.Intrinsic.REAL assert symbol.datatype.precision == ScalarType.Precision.SINGLE assert len(symbol.shape) == 2 assert isinstance(symbol.shape[0], Literal) assert symbol.shape[0].value == "1" assert symbol.shape[0].datatype.intrinsic == ScalarType.Intrinsic.INTEGER assert symbol.shape[0].datatype.precision == ScalarType.Precision.UNDEFINED assert isinstance(symbol.shape[1], Literal) assert symbol.shape[1].value == "2" assert symbol.shape[1].datatype.intrinsic == ScalarType.Intrinsic.INTEGER assert symbol.shape[1].datatype.precision == ScalarType.Precision.UNDEFINED assert not symbol.constant_value # Now check constant_value new_symbol.constant_value = 3 assert isinstance(symbol.shape[0], Literal) assert symbol.shape[0].value == "1" assert symbol.shape[0].datatype.intrinsic == ScalarType.Intrinsic.INTEGER assert symbol.shape[0].datatype.precision == ScalarType.Precision.UNDEFINED assert isinstance(symbol.shape[1], Literal) assert symbol.shape[1].value == "2" assert symbol.shape[1].datatype.intrinsic == ScalarType.Intrinsic.INTEGER assert symbol.shape[1].datatype.precision == ScalarType.Precision.UNDEFINED assert not symbol.constant_value
def test_get_array_bound_error(): '''Test that the _get_array_bound() utility function raises the expected exception if the shape of the array's symbol is not supported.''' array_type = ArrayType(REAL_TYPE, [10]) array_symbol = DataSymbol("x", array_type) reference = Reference(array_symbol) array_type._shape = [0.2] with pytest.raises(TransformationError) as excinfo: _get_array_bound(reference, 0) assert ("Transformation Error: Unsupported index type 'float' found for " "dimension 1 of array 'x'." in str(excinfo.value))
def test_datasymbol_initialisation(): '''Test that a DataSymbol instance can be created when valid arguments are given, otherwise raise relevant exceptions.''' # Test with valid arguments assert isinstance(DataSymbol('a', REAL_SINGLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', REAL_DOUBLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', REAL4_TYPE), DataSymbol) kind = DataSymbol('r_def', INTEGER_SINGLE_TYPE) real_kind_type = ScalarType(ScalarType.Intrinsic.REAL, kind) assert isinstance(DataSymbol('a', real_kind_type), DataSymbol) # real constants are not currently supported assert isinstance(DataSymbol('a', INTEGER_SINGLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', INTEGER_DOUBLE_TYPE, constant_value=0), DataSymbol) assert isinstance(DataSymbol('a', INTEGER4_TYPE), DataSymbol) assert isinstance(DataSymbol('a', CHARACTER_TYPE), DataSymbol) assert isinstance(DataSymbol('a', CHARACTER_TYPE, constant_value="hello"), DataSymbol) assert isinstance(DataSymbol('a', BOOLEAN_TYPE), DataSymbol) assert isinstance(DataSymbol('a', BOOLEAN_TYPE, constant_value=False), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [ArrayType.Extent.ATTRIBUTE]) assert isinstance(DataSymbol('a', array_type), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [3]) assert isinstance(DataSymbol('a', array_type), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [3, ArrayType.Extent.ATTRIBUTE]) assert isinstance(DataSymbol('a', array_type), DataSymbol) assert isinstance(DataSymbol('a', REAL_SINGLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', REAL8_TYPE), DataSymbol) dim = DataSymbol('dim', INTEGER_SINGLE_TYPE, interface=UnresolvedInterface()) array_type = ArrayType(REAL_SINGLE_TYPE, [Reference(dim)]) assert isinstance(DataSymbol('a', array_type), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [3, Reference(dim), ArrayType.Extent.ATTRIBUTE]) assert isinstance(DataSymbol('a', array_type), DataSymbol) assert isinstance( DataSymbol('a', REAL_SINGLE_TYPE, interface=ArgumentInterface( ArgumentInterface.Access.READWRITE)), DataSymbol) assert isinstance( DataSymbol('a', REAL_SINGLE_TYPE, visibility=Symbol.Visibility.PRIVATE), DataSymbol) assert isinstance(DataSymbol('field', DataTypeSymbol("field_type", DeferredType())), DataSymbol)
def test_arraytype_str_invalid(): '''Test that the ArrayType class str method raises an exception if an unsupported dimension type is found. ''' scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, 4) array_type = ArrayType(scalar_type, [10]) # Make one of the array dimensions an unsupported type array_type._shape = [None] with pytest.raises(InternalError) as excinfo: _ = str(array_type) assert ("PSyclone internal error: ArrayType shape list elements can only " "be 'DataNode', or 'ArrayType.Extent', but found 'NoneType'." in str(excinfo.value))
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_check_variable(): '''Test the _check_variable utility method behaves as expected''' with pytest.raises(GenerationError) as info: Loop._check_variable(None) assert ("variable property in Loop class should be a DataSymbol but " "found 'NoneType'." in str(info.value)) with pytest.raises(GenerationError) as info: Loop._check_variable("hello") assert ("variable property in Loop class should be a DataSymbol but " "found 'str'." in str(info.value)) array_type = ArrayType(INTEGER_TYPE, shape=[10, 20]) array_symbol = DataSymbol("my_array", array_type) with pytest.raises(GenerationError) as info: Loop._check_variable(array_symbol) assert ("variable property in Loop class should be a ScalarType but " "found 'ArrayType'." in str(info.value)) scalar_symbol = DataSymbol("my_array", REAL_TYPE) with pytest.raises(GenerationError) as info: Loop._check_variable(scalar_symbol) assert ("variable property in Loop class should be a scalar integer but " "found 'REAL'." in str(info.value)) scalar_symbol = DataSymbol("my_array", INTEGER_TYPE) assert Loop._check_variable(scalar_symbol) is None
def test_literal_init(): '''Test the initialisation Literal object with ScalarType and ArrayType and different precisions. ''' array_type = ArrayType(REAL_DOUBLE_TYPE, [10, 10]) literal = Literal("1", array_type) assert literal.value == "1" assert isinstance(literal.datatype, ArrayType) assert literal.datatype.intrinsic == ScalarType.Intrinsic.REAL assert literal.datatype.precision == ScalarType.Precision.DOUBLE assert len(literal.datatype.shape) == 2 assert isinstance(literal.datatype.shape[0], Literal) assert literal.datatype.shape[0].value == '10' assert (literal.datatype.shape[0].datatype.intrinsic == ScalarType.Intrinsic.INTEGER) assert (literal.datatype.shape[0].datatype.precision == ScalarType.Precision.UNDEFINED) assert isinstance(literal.datatype.shape[1], Literal) assert literal.datatype.shape[1].value == '10' assert (literal.datatype.shape[1].datatype.intrinsic == ScalarType.Intrinsic.INTEGER) assert (literal.datatype.shape[1].datatype.precision == ScalarType.Precision.UNDEFINED) literal = Literal("true", BOOLEAN_TYPE) assert literal.value == "true" assert literal.datatype.intrinsic == ScalarType.Intrinsic.BOOLEAN assert literal.datatype.precision == ScalarType.Precision.UNDEFINED literal = Literal("false", BOOLEAN_TYPE) assert literal.value == "false" assert literal.datatype.intrinsic == ScalarType.Intrinsic.BOOLEAN assert literal.datatype.precision == ScalarType.Precision.UNDEFINED
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_datasymbol_can_be_printed(): '''Test that a DataSymbol instance can always be printed. (i.e. is initialised fully.)''' symbol = DataSymbol("sname", REAL_SINGLE_TYPE) assert "sname: <Scalar<REAL, SINGLE>, Local>" in str(symbol) sym1 = DataSymbol("s1", INTEGER_SINGLE_TYPE, interface=UnresolvedInterface()) assert "s1: <Scalar<INTEGER, SINGLE>, Unresolved>" in str(sym1) array_type = ArrayType(REAL_SINGLE_TYPE, [ArrayType.Extent.ATTRIBUTE, 2, Reference(sym1)]) sym2 = DataSymbol("s2", array_type) assert ("s2: <Array<Scalar<REAL, SINGLE>, shape=['ATTRIBUTE', " "Literal[value:'2', Scalar<INTEGER, UNDEFINED>], " "Reference[name:'s1']]>, Local>" in str(sym2)) my_mod = ContainerSymbol("my_mod") sym3 = DataSymbol("s3", REAL_SINGLE_TYPE, interface=GlobalInterface(my_mod)) assert ("s3: <Scalar<REAL, SINGLE>, Global(container='my_mod')>" in str(sym3)) sym3 = DataSymbol("s3", INTEGER_SINGLE_TYPE, constant_value=12) assert ("s3: <Scalar<INTEGER, SINGLE>, Local, " "constant_value=Literal" "[value:'12', Scalar<INTEGER, SINGLE>]>" in str(sym3)) sym4 = DataSymbol("s4", INTEGER_SINGLE_TYPE, interface=UnresolvedInterface()) assert "s4: <Scalar<INTEGER, SINGLE>, Unresolved>" in str(sym4)
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_datasymbol_copy_properties(): '''Test that the DataSymbol copy_properties method works as expected.''' array_type = ArrayType(REAL_SINGLE_TYPE, [1, 2]) symbol = DataSymbol("myname", array_type, constant_value=None, interface=ArgumentInterface( ArgumentInterface.Access.READWRITE)) # Check an exception is raised if an incorrect argument is passed in with pytest.raises(TypeError) as excinfo: symbol.copy_properties(None) assert ("Argument should be of type 'DataSymbol' but found 'NoneType'." "") in str(excinfo.value) new_symbol = DataSymbol("other_name", INTEGER_SINGLE_TYPE, constant_value=7) symbol.copy_properties(new_symbol) assert symbol.name == "myname" assert symbol.datatype.intrinsic == ScalarType.Intrinsic.INTEGER assert symbol.datatype.precision == ScalarType.Precision.SINGLE assert symbol.is_local assert isinstance(symbol.constant_value, Literal) assert symbol.constant_value.value == "7" assert ( symbol.constant_value.datatype.intrinsic == symbol.datatype.intrinsic) assert ( symbol.constant_value.datatype.precision == symbol.datatype.precision)
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 = Array.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_literal_can_be_printed(): '''Test that a Literal instance can always be printed (i.e. is initialised fully)''' array_type = ArrayType(REAL_DOUBLE_TYPE, [10, 10]) literal = Literal("1", array_type) assert ("Literal[value:'1', Array<Scalar<REAL, DOUBLE>, " "shape=[10, 10]>]" in str(literal))
def test_arraytype(): '''Test that the ArrayType class __init__ works as expected.''' datatype = ScalarType(ScalarType.Intrinsic.INTEGER, 4) shape = [10, 10] array_type = ArrayType(datatype, shape) assert isinstance(array_type, ArrayType) assert array_type.shape == shape assert array_type._datatype == datatype
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_arraytype_datatypesymbol(): ''' Test that we can correctly create an ArrayType when the type of the elements is specified as a DataTypeSymbol. ''' tsym = DataTypeSymbol("my_type", DeferredType()) atype = ArrayType(tsym, [5]) assert isinstance(atype, ArrayType) assert len(atype.shape) == 1 assert atype.intrinsic is tsym assert atype.precision is None
def test_arraytype_invalid_datatype(): '''Test that the ArrayType class raises an exception when the datatype argument is the wrong type. ''' with pytest.raises(TypeError) as excinfo: _ = ArrayType(None, None) assert ("ArrayType expected 'datatype' argument to be of type DataType " "or DataTypeSymbol but found 'NoneType'." in str(excinfo.value))
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_gen_declaration(): '''Check the CWriter class gen_declaration method produces the expected declarations. ''' cwriter = CWriter() # Basic entries symbol = DataSymbol("dummy1", INTEGER_TYPE) result = cwriter.gen_declaration(symbol) assert result == "int dummy1" symbol = DataSymbol("dummy1", CHARACTER_TYPE) result = cwriter.gen_declaration(symbol) assert result == "char dummy1" symbol = DataSymbol("dummy1", BOOLEAN_TYPE) result = cwriter.gen_declaration(symbol) assert result == "bool dummy1" # Array argument array_type = ArrayType(REAL_TYPE, [2, ArrayType.Extent.ATTRIBUTE, 2]) symbol = DataSymbol("dummy2", array_type, interface=ArgumentInterface( ArgumentInterface.Access.READ)) result = cwriter.gen_declaration(symbol) assert result == "double * restrict dummy2" # Array with unknown access array_type = ArrayType(INTEGER_TYPE, [2, ArrayType.Extent.ATTRIBUTE, 2]) symbol = DataSymbol("dummy2", array_type, interface=ArgumentInterface( ArgumentInterface.Access.UNKNOWN)) result = cwriter.gen_declaration(symbol) assert result == "int * restrict dummy2" # Check invalid datatype produces and error symbol._datatype = "invalid" with pytest.raises(NotImplementedError) as error: _ = cwriter.gen_declaration(symbol) assert "Could not generate the C definition for the variable 'dummy2', " \ "type 'invalid' is currently not supported." in str(error.value)
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_validate3(): '''Check that the Matmul2Code validate method raises the expected exception when the supplied node is a MATMUL binary operation but doesn't have an assignment as an ancestor. ''' trans = Matmul2CodeTrans() vector_type = ArrayType(REAL_TYPE, [10]) array_type = ArrayType(REAL_TYPE, [10, 10]) vector = Reference(DataSymbol("x", vector_type)) array = Reference(DataSymbol("y", array_type)) matmul = BinaryOperation.create(BinaryOperation.Operator.MATMUL, array, vector) with pytest.raises(TransformationError) as excinfo: trans.validate(matmul) assert ("Transformation Error: Error in Matmul2CodeTrans transformation. " "This transformation requires the operator to be part of an " "assignment statement, but no such assignment was found." in str(excinfo.value))
def test_arraytype_invalid_shape(): '''Test that the ArrayType class raises an exception when the shape argument is the wrong type. ''' scalar_type = ScalarType(ScalarType.Intrinsic.REAL, 4) with pytest.raises(TypeError) as excinfo: _ = ArrayType(scalar_type, None) assert ("ArrayType 'shape' must be of type list but " "found 'NoneType'." in str(excinfo.value))
def test_arraytype_datatypesymbol_only(): ''' Test that we currently refuse to make an ArrayType with an intrinsic type of StructureType. (This limitation is the subject of #1031.) ''' with pytest.raises(NotImplementedError) as err: _ = ArrayType(StructureType.create( [("nx", INTEGER_TYPE, Symbol.Visibility.PUBLIC)]), [5]) assert ("When creating an array of structures, the type of those " "structures must be supplied as a DataTypeSymbol but got a " "StructureType instead." in str(err.value))
def test_arraytype_str(): '''Test that the ArrayType class str method works as expected.''' scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, ScalarType.Precision.UNDEFINED) data_symbol = DataSymbol("var", scalar_type) data_type = ArrayType(scalar_type, [ 10, data_symbol, ArrayType.Extent.DEFERRED, ArrayType.Extent.ATTRIBUTE ]) assert (str(data_type) == "Array<Scalar<INTEGER, UNDEFINED>," " shape=[10, var, 'DEFERRED', 'ATTRIBUTE']>")
def test_arraytype_str(): '''Test that the ArrayType class str method works as expected.''' scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, ScalarType.Precision.UNDEFINED) data_symbol = DataSymbol("var", scalar_type, constant_value=20) data_type = ArrayType(scalar_type, [10, Reference(data_symbol), ArrayType.Extent.DEFERRED, ArrayType.Extent.ATTRIBUTE]) assert (str(data_type) == "Array<Scalar<INTEGER, UNDEFINED>," " shape=[Literal[value:'10', Scalar<INTEGER, UNDEFINED>], " "Reference[name:'var'], 'DEFERRED', 'ATTRIBUTE']>")