def test_fusetrans_error_not_same_parent(): ''' Check that we reject attempts to fuse loops which don't share the same parent ''' loop1 = Loop.create(DataSymbol("i", INTEGER_TYPE), Literal("1", INTEGER_TYPE), Literal("10", INTEGER_TYPE), Literal("1", INTEGER_TYPE), [Return()]) sch1 = Schedule() sch1.addchild(loop1) sch2 = Schedule() loop2 = Loop.create(DataSymbol("j", INTEGER_TYPE), Literal("1", INTEGER_TYPE), Literal("10", INTEGER_TYPE), Literal("1", INTEGER_TYPE), [Return()]) sch2.addchild(loop2) fuse = LoopFuseTrans() # Try to fuse loops with different parents with pytest.raises(TransformationError) as err: fuse.validate(loop1, loop2) assert ("Error in LoopFuseTrans transformation. Loops do not have the " "same parent" in str(err.value))
def test_return_children_validation(): '''Test that children added to Return are validated. A Return node does not accept any children. ''' return_stmt = Return() return_stmt1 = Return() with pytest.raises(GenerationError) as excinfo: return_stmt.addchild(return_stmt1) assert ("Item 'Return' can't be child 0 of 'Return'. Return is a" " LeafNode and doesn't accept children.") in str(excinfo.value)
def test_create_loop_validate(): ''' Check that the validate() method works as expected. ''' trans = CreateNemoLoopTrans() with pytest.raises(TransformationError) as err: trans.validate(Return()) assert ("supplied node should be a PSyIR Loop but found 'Return'" in str(err.value))
def test_create_invokesched_validate(): ''' Check that the validate() method works as expected. ''' trans = CreateNemoInvokeScheduleTrans() with pytest.raises(TransformationError) as err: trans.validate(Return()) assert ("supplied node should be a PSyIR Routine but found 'Return'" in str(err.value))
def test_node_constructor_with_parent(): ''' Check that the node constructor parent parameter works as expected. ''' parent = Schedule() wrong_parent = Schedule() # By default no parent reference is given node = Statement() assert node.parent is None assert node.has_constructor_parent is False # The parent argument can predefine the parent reference node = Return(parent=parent) assert node.parent is parent assert node.has_constructor_parent is True # Then only an addition to this predefined parent is accepted with pytest.raises(GenerationError) as err: wrong_parent.addchild(node) assert ("'Schedule' cannot be set as parent of 'Return' because its " "constructor predefined the parent reference to a different " "'Schedule' node." in str(err.value)) # Once given the proper parent, it can act as a regular node parent.addchild(node) assert node.parent is parent assert node.has_constructor_parent is False wrong_parent.addchild(node.detach()) assert node.parent is wrong_parent
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_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_cw_return(): '''Check the CWriter class return method correctly prints out the C representation. ''' cwriter = CWriter() result = cwriter(Return()) assert "return;\n" in result
def lower_to_language_level(self): ''' MyDSLNode lowers to a return statement and adds a symbol if it is inside an scoping region. ''' # This will break if this Node does not have a parent with # a scope. This is intentional to cause an error during the # lowering step. self.scope.symbol_table.add(DataSymbol("val", REAL_TYPE)) self.replace_with(Return())
def test_cw_ifblock(): '''Check the CWriter class ifblock method correctly prints out the C representation. ''' from psyclone.psyir.nodes import IfBlock # Try with just an IfBlock node ifblock = IfBlock() cwriter = CWriter() with pytest.raises(VisitorError) as err: _ = cwriter(ifblock) assert ("IfBlock malformed or incomplete. It should have " "at least 2 children, but found 0." in str(err.value)) # Add the if condition ifblock.addchild(Reference(DataSymbol('a', REAL_TYPE), parent=ifblock)) with pytest.raises(VisitorError) as err: _ = cwriter(ifblock) assert ("IfBlock malformed or incomplete. It should have " "at least 2 children, but found 1." in str(err.value)) # Fill the if_body and else_body ifblock.addchild(Schedule(parent=ifblock)) ifblock.addchild(Schedule(parent=ifblock)) ifblock.if_body.addchild(Return(parent=ifblock.if_body)) condition = Reference(DataSymbol('b', REAL_TYPE)) then_content = [Return()] else_content = [Return()] ifblock2 = IfBlock.create(condition, then_content, else_content) ifblock2.parent = ifblock.if_body ifblock.else_body.addchild(ifblock2) result = cwriter(ifblock) assert result == ("if (a) {\n" " return;\n" "} else {\n" " if (b) {\n" " return;\n" " } else {\n" " return;\n" " }\n" "}\n")
def test_ifblock_can_be_printed(): '''Test that an IfBlock instance can always be printed (i.e. is initialised fully)''' condition = Reference(DataSymbol('condition1', BOOLEAN_TYPE)) then_content = [Return()] ifblock = IfBlock.create(condition, then_content) assert "If[]\n" in str(ifblock) assert "condition1" in str(ifblock) # Test condition is printed assert "Return[]" in str(ifblock) # Test if_body is printed
def test_auto_invoke_no_return(capsys): ''' Check that using the auto-invoke profiling option does not add any profiling if the invoke contains a Return anywhere other than as the last statement. ''' 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) assign1 = Assignment.create(Reference(arg1), zero) assign2 = Assignment.create(Reference(arg1), zero.copy()) # Create Schedule with Return at the start. kschedule = KernelSchedule.create( "work1", symbol_table, [Return(), assign1, assign2]) Profiler.add_profile_nodes(kschedule, Loop) # No profiling should have been added assert not kschedule.walk(ProfileNode) _, err = capsys.readouterr() assert ("Not adding profiling to routine 'work1' because it contains one " "or more Return statements" in err) # Create Schedule with Return in the middle. kschedule = KernelSchedule.create( "work2", symbol_table, [assign1.copy(), Return(), assign2.copy()]) Profiler.add_profile_nodes(kschedule, Loop) # No profiling should have been added assert not kschedule.walk(ProfileNode) _, err = capsys.readouterr() assert ("Not adding profiling to routine 'work2' because it contains one " "or more Return statements" in err) # Create Schedule with a Return at the end as well as in the middle. kschedule = KernelSchedule.create( "work3", symbol_table, [assign1.copy(), Return(), assign2.copy(), Return()]) Profiler.add_profile_nodes(kschedule, Loop) # No profiling should have been added assert not kschedule.walk(ProfileNode) _, err = capsys.readouterr() assert ("Not adding profiling to routine 'work3' because it contains one " "or more Return statements" in err)
def test_datasymbol_constant_value_setter_invalid(): '''Test that a DataSymbol constant value setter raises the appropriate error if an invalid value and/or datatype are given.''' # Test with invalid constant values sym = DataSymbol('a', DeferredType()) with pytest.raises(ValueError) as error: sym.constant_value = 1.0 assert ("Error setting constant value for symbol 'a'. A DataSymbol with " "a constant value must be a scalar or an array but found " "'DeferredType'." in str(error.value)) # Test with invalid constant expressions ct_expr = Return() with pytest.raises(ValueError) as error: _ = DataSymbol('a', INTEGER_SINGLE_TYPE, constant_value=ct_expr) assert "Error setting constant value for symbol 'a'. PSyIR static " \ "expressions can only contain PSyIR literal, operation or reference" \ " nodes but found:" in str(error.value) with pytest.raises(ValueError) as error: DataSymbol('a', INTEGER_SINGLE_TYPE, interface=ArgumentInterface(), constant_value=9) assert ("Error setting constant value for symbol 'a'. A DataSymbol with " "an ArgumentInterface can not have a constant value." in str(error.value)) with pytest.raises(ValueError) as error: DataSymbol('a', INTEGER_SINGLE_TYPE, constant_value=9.81) assert ("Error setting constant value for symbol 'a'. This DataSymbol " "instance datatype is 'Scalar<INTEGER, SINGLE>' which " "means the constant value is expected to be") in str(error.value) assert "'int'>' but found " in str(error.value) assert "'float'>'." in str(error.value) with pytest.raises(ValueError) as error: DataSymbol('a', CHARACTER_TYPE, constant_value=42) assert ("Error setting constant value for symbol 'a'. This DataSymbol " "instance datatype is 'Scalar<CHARACTER, UNDEFINED>' which " "means the constant value is expected to be") in str(error.value) assert "'str'>' but found " in str(error.value) assert "'int'>'." in str(error.value) with pytest.raises(ValueError) as error: DataSymbol('a', BOOLEAN_TYPE, constant_value="hello") assert ("Error setting constant value for symbol 'a'. This DataSymbol " "instance datatype is 'Scalar<BOOLEAN, UNDEFINED>' which " "means the constant value is expected to be") in str(error.value) assert "'bool'>' but found " in str(error.value) assert "'str'>'." in str(error.value)
def test_children_is_orphan_validation(): ''' Test that all kinds of children addition operations make sure that a child is orphan before accepting it as its own child. ''' # Create 2 schedules and add a child in the first Schedule schedule1 = Schedule() schedule2 = Schedule() statement = Return(parent=schedule1) schedule1.addchild(statement) # Try to move the child without removing the parent connection first errmsg = ("Item 'Return' can't be added as child of 'Schedule' because " "it is not an orphan. It already has a 'Schedule' as a parent.") with pytest.raises(GenerationError) as error: schedule2.addchild(statement) assert errmsg in str(error.value) with pytest.raises(GenerationError) as error: schedule2.children.append(statement) assert errmsg in str(error.value) with pytest.raises(GenerationError) as error: schedule2.children.insert(0, statement) assert errmsg in str(error.value) with pytest.raises(GenerationError) as error: schedule2.children.extend([statement]) assert errmsg in str(error.value) with pytest.raises(GenerationError) as error: schedule2.children = [statement] assert errmsg in str(error.value) schedule2.addchild(Return()) with pytest.raises(GenerationError) as error: schedule2.children[0] = statement assert errmsg in str(error.value) # It can be added when it has been detached from its previous parent schedule2.addchild(statement.detach())
def test_children_is_orphan_same_parent(): ''' Test children addition operations with a node that is not an orphan and already belongs to the parent to which it is being added.''' # Create 2 schedules and add a child in the first Schedule schedule1 = Schedule() statement = Return(parent=schedule1) schedule1.addchild(statement) with pytest.raises(GenerationError) as error: schedule1.addchild(statement) assert ("Item 'Return' can't be added as child of 'Schedule' because " "it is not an orphan. It already has a 'Schedule' as a parent." in str(error.value))
def test_psyirvisitor_visit_return_node(): '''Check that when a return PSyIR node is found the actual method called is 'return_node'. This is done to avoid clashing with the Python keyword. ''' return_node = Return() test_visitor = PSyIRVisitor() with pytest.raises(VisitorError) as excinfo: _ = test_visitor(return_node) assert ("Visitor Error: Unsupported node 'Return' found: method names " "attempted were ['return_node', 'statement_node', 'node_node']." in str(excinfo.value))
def test_fusetrans_error_incomplete(): ''' Check that we reject attempts to fuse loops which are incomplete. ''' from psyclone.psyir.nodes import Return from psyclone.transformations import LoopFuseTrans sch = Schedule() loop1 = Loop(variable=DataSymbol("i", INTEGER_TYPE), parent=sch) loop2 = Loop(variable=DataSymbol("j", INTEGER_TYPE), parent=sch) sch.addchild(loop1) sch.addchild(loop2) fuse = LoopFuseTrans() # Check first loop with pytest.raises(TransformationError) as err: fuse.validate(loop1, loop2) assert ("Error in LoopFuseTrans transformation. The target loop must have " "four children but found: []" in str(err.value)) loop1.addchild(Literal("start", INTEGER_TYPE, parent=loop1)) loop1.addchild(Literal("stop", INTEGER_TYPE, parent=loop1)) loop1.addchild(Literal("step", INTEGER_TYPE, parent=loop1)) loop1.addchild(Schedule(parent=loop1)) loop1.loop_body.addchild(Return(parent=loop1.loop_body)) # Check second loop with pytest.raises(TransformationError) as err: fuse.validate(loop1, loop2) assert ("Error in LoopFuseTrans transformation. The target loop must have " "four children but found: []" in str(err.value)) loop2.addchild(Literal("start", INTEGER_TYPE, parent=loop2)) loop2.addchild(Literal("stop", INTEGER_TYPE, parent=loop2)) loop2.addchild(Literal("step", INTEGER_TYPE, parent=loop2)) loop2.addchild(Schedule(parent=loop2)) loop2.loop_body.addchild(Return(parent=loop2.loop_body)) # Validation should now pass fuse.validate(loop1, loop2)
def test_ifblock_properties(): '''Test that an IfBlock node properties can be retrieved''' ifblock = IfBlock() # Condition can't be retrieved before it is added as a child. with pytest.raises(InternalError) as err: _ = ifblock.condition assert("IfBlock malformed or incomplete. It should have " "at least 2 children, but found 0." in str(err.value)) ref1 = Reference(DataSymbol('condition1', BOOLEAN_TYPE), parent=ifblock) ifblock.addchild(ref1) # If_body can't be retrieved before is added as a child. with pytest.raises(InternalError) as err: _ = ifblock.if_body assert("IfBlock malformed or incomplete. It should have " "at least 2 children, but found 1." in str(err.value)) sch = Schedule() ifblock.addchild(sch) ret = Return() sch.addchild(ret) # Now we can retrieve the condition and the if_body, but else is empty assert ifblock.condition is ref1 assert ifblock.if_body[0] is ret assert not ifblock.else_body sch2 = Schedule() ifblock.addchild(sch2) ret2 = Return() sch2.addchild(ret2) # Now we can retrieve else_body assert ifblock.else_body[0] is ret2
def test_ifblock_view_indices(capsys): ''' Check that the view method only displays indices on the nodes in the body (and else body) of an IfBlock. ''' colouredif = colored("If", IfBlock._colour) colouredreturn = colored("Return", Return._colour) colouredref = colored("Reference", Reference._colour) condition = Reference(DataSymbol('condition1', REAL_SINGLE_TYPE)) then_content = [Return()] ifblock = IfBlock.create(condition, then_content) ifblock.view() output, _ = capsys.readouterr() # Check that we only prepend child indices where it makes sense assert colouredif + "[]" in output assert "0: " + colouredreturn in output assert ": " + colouredref not in output
def test_container_children_validation(): '''Test that children added to Container are validated. Container accepts just Container and kernelSchedule as children. ''' container = Container.create("container", SymbolTable(), []) # Valid children container2 = Container.create("container2", SymbolTable(), []) container.addchild(container2) # Invalid children (e.g. Return Statement) ret = Return() with pytest.raises(GenerationError) as excinfo: container.addchild(ret) assert ("Item 'Return' can't be child 1 of 'Container'. The valid format" " is: '[Container | KernelSchedule | InvokeSchedule]*'." "" in str(excinfo.value))
def test_auto_invoke_return_last_stmt(parser): ''' Check that using the auto-invoke profiling option avoids including a return statement within the profiling region if it is the last statement in the routine. ''' symbol_table = SymbolTable() arg1 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE) zero = Literal("0.0", REAL_TYPE) assign1 = Assignment.create(Reference(arg1), zero) kschedule = KernelSchedule.create("work", symbol_table, [assign1, Return()]) # Double-check that the tree is as we expect assert isinstance(kschedule[-1], Return) Profiler.set_options([Profiler.INVOKES]) Profiler.add_profile_nodes(kschedule, Loop) # The Return should be a sibling of the ProfileNode rather than a child assert isinstance(kschedule[0], ProfileNode) assert isinstance(kschedule[0].children[0].children[0], Assignment) assert isinstance(kschedule[1], Return)
def test_lower_named_profile_node(): ''' Test that the lower_to_language_level method behaves as expected when a ProfileNode has pre-set names for the module and region. ''' Profiler.set_options([Profiler.INVOKES]) symbol_table = SymbolTable() arg1 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE) assign1 = Assignment.create(Reference(arg1), Literal("0.0", REAL_TYPE)) kschedule = KernelSchedule.create("work1", symbol_table, [assign1, Return()]) Profiler.add_profile_nodes(kschedule, Loop) pnode = kschedule.walk(ProfileNode)[0] # Manually set the module and region names (to save using a transformation) pnode._module_name = "my_mod" pnode._region_name = "first" kschedule.lower_to_language_level() cblocks = kschedule.walk(CodeBlock) assert ("PreStart('my_mod', 'first', 0, 0)" in str(cblocks[0].get_ast_nodes[0]))
def test_naryoperation_children_validation(): '''Test that children added to NaryOperation are validated. NaryOperations accepts DataNodes nodes as children. ''' nary = NaryOperation(NaryOperation.Operator.MAX) literal1 = Literal("1", INTEGER_SINGLE_TYPE) literal2 = Literal("2", INTEGER_SINGLE_TYPE) literal3 = Literal("3", INTEGER_SINGLE_TYPE) statement = Return() # DataNodes are valid nary.addchild(literal1) nary.addchild(literal2) nary.addchild(literal3) # Statements are not valid with pytest.raises(GenerationError) as excinfo: nary.addchild(statement) assert ("Item 'Return' can't be child 3 of 'NaryOperation'. The valid " "format is: '[DataNode]+'.") in str(excinfo.value)
def test_unaryoperation_children_validation(): '''Test that children added to unaryOperation are validated. UnaryOperations accept just 1 DataNode as child. ''' operation = UnaryOperation(UnaryOperation.Operator.SIN) literal1 = Literal("1", INTEGER_SINGLE_TYPE) literal2 = Literal("2", INTEGER_SINGLE_TYPE) statement = Return() # Statements are not valid with pytest.raises(GenerationError) as excinfo: operation.addchild(statement) assert ("Item 'Return' can't be child 0 of 'UnaryOperation'. The valid " "format is: 'DataNode'.") in str(excinfo.value) # First DataNodes is valid, but not subsequent ones operation.addchild(literal1) with pytest.raises(GenerationError) as excinfo: operation.addchild(literal2) assert ("Item 'Literal' can't be child 1 of 'UnaryOperation'. The valid " "format is: 'DataNode'.") in str(excinfo.value)
def test_psy_data_node_children_validation(): '''Test that children added to PSyDataNode are validated. PSyDataNode accepts just one Schedule as its child. ''' psy_node = PSyDataNode.create([], SymbolTable()) del psy_node.children[0] # Invalid children (e.g. Return Statement) ret = Return() with pytest.raises(GenerationError) as excinfo: psy_node.addchild(ret) assert ("Item 'Return' can't be child 0 of 'PSyData'. The valid format" " is: 'Schedule'." in str(excinfo.value)) # Valid children psy_node.addchild(Schedule()) # Additional children with pytest.raises(GenerationError) as excinfo: psy_node.addchild(Schedule()) assert ("Item 'Schedule' can't be child 1 of 'PSyData'. The valid format" " is: 'Schedule'." in str(excinfo.value))
def test_oclw_kernelschedule(): '''Check the OpenCLWriter class kernelschedule_node visitor produces the expected OpenCL code. ''' # The kernelschedule OpenCL Backend relies on abstract methods that # need to be implemented by the APIs. A generic kernelschedule will # produce a NotImplementedError. oclwriter = OpenCLWriter() kschedule = KernelSchedule("kname") with pytest.raises(NotImplementedError) as error: _ = oclwriter(kschedule) assert "Abstract property. Which symbols are data arguments is " \ "API-specific." in str(error.value) # Mock abstract properties. (pytest monkeypatch does not work # with properties, used sub-class instead) class MockSymbolTable(SymbolTable): ''' Mock needed abstract methods of the Symbol Table ''' @property def iteration_indices(self): return self.argument_list[:2] @property def data_arguments(self): return self.argument_list[2:] kschedule.symbol_table.__class__ = MockSymbolTable # Create a sample symbol table and kernel schedule interface = ArgumentInterface(ArgumentInterface.Access.UNKNOWN) i = DataSymbol('i', INTEGER_TYPE, interface=interface) j = DataSymbol('j', INTEGER_TYPE, interface=interface) array_type = ArrayType(REAL_TYPE, [10, 10]) data1 = DataSymbol('data1', array_type, interface=interface) data2 = DataSymbol('data2', array_type, interface=interface) kschedule.symbol_table.add(i) kschedule.symbol_table.add(j) kschedule.symbol_table.add(data1) kschedule.symbol_table.add(data2) kschedule.symbol_table.specify_argument_list([i, j, data1, data2]) kschedule.addchild(Return(parent=kschedule)) result = oclwriter(kschedule) assert result == "" \ "__kernel void kname(\n" \ " __global double * restrict data1,\n" \ " __global double * restrict data2\n" \ " ){\n" \ " int data1LEN1 = get_global_size(0);\n" \ " int data1LEN2 = get_global_size(1);\n" \ " int data2LEN1 = get_global_size(0);\n" \ " int data2LEN2 = get_global_size(1);\n" \ " int i = get_global_id(0);\n" \ " int j = get_global_id(1);\n" \ " return;\n" \ "}\n\n" # Set a local_size value different to 1 into the KernelSchedule oclwriter = OpenCLWriter(kernels_local_size=4) result = oclwriter(kschedule) assert result == "" \ "__attribute__((reqd_work_group_size(4, 1, 1)))\n" \ "__kernel void kname(\n" \ " __global double * restrict data1,\n" \ " __global double * restrict data2\n" \ " ){\n" \ " int data1LEN1 = get_global_size(0);\n" \ " int data1LEN2 = get_global_size(1);\n" \ " int data2LEN1 = get_global_size(0);\n" \ " int data2LEN2 = get_global_size(1);\n" \ " int i = get_global_id(0);\n" \ " int j = get_global_id(1);\n" \ " return;\n" \ "}\n\n" # Add a symbol with a deferred interface and check that this raises the # expected error array_type = ArrayType(REAL_TYPE, [10, 10]) kschedule.symbol_table.add( DataSymbol('broken', array_type, interface=UnresolvedInterface())) with pytest.raises(VisitorError) as err: _ = oclwriter(kschedule) assert ("symbol table contains unresolved data entries (i.e. that have no " "defined Interface) which are not used purely to define the " "precision of other symbols: 'broken'" in str(err.value))
def test_children_validation(): ''' Test that nodes are validated when inserted as children of other nodes. For simplicity we use Node subclasses to test this functionality across a range of possible operations. The specific logic of each validate method will be tested individually inside each Node test file. ''' assignment = Assignment() return_stmt = Return() reference = Reference(DataSymbol("a", INTEGER_TYPE)) assert isinstance(assignment.children, (ChildrenList, list)) # Try adding a invalid child (e.g. a return_stmt into an assingment) with pytest.raises(GenerationError) as error: assignment.addchild(return_stmt) assert "Item 'Return' can't be child 0 of 'Assignment'. The valid format" \ " is: 'DataNode, DataNode'." in str(error.value) # The same behaviour occurs when list insertion operations are used. with pytest.raises(GenerationError): assignment.children.append(return_stmt) with pytest.raises(GenerationError): assignment.children[0] = return_stmt with pytest.raises(GenerationError): assignment.children.insert(0, return_stmt) with pytest.raises(GenerationError): assignment.children.extend([return_stmt]) with pytest.raises(GenerationError): assignment.children = assignment.children + [return_stmt] # Valid nodes are accepted assignment.addchild(reference) # Check displaced items are also be checked when needed start = Literal("0", INTEGER_TYPE) stop = Literal("1", INTEGER_TYPE) step = Literal("2", INTEGER_TYPE) child_node = Assignment.create(Reference(DataSymbol("tmp", REAL_TYPE)), Reference(DataSymbol("i", REAL_TYPE))) loop_variable = DataSymbol("idx", INTEGER_TYPE) loop = Loop.create(loop_variable, start, stop, step, [child_node]) with pytest.raises(GenerationError): loop.children.insert(1, Literal("0", INTEGER_TYPE)) with pytest.raises(GenerationError): loop.children.remove(stop) with pytest.raises(GenerationError): del loop.children[2] with pytest.raises(GenerationError): loop.children.pop(2) with pytest.raises(GenerationError): loop.children.reverse() # But the in the right circumstances they work fine assert isinstance(loop.children.pop(), Schedule) loop.children.reverse() assert loop.children[0].value == "2"
def test_return_node_str(): ''' Check the node_str method of the Return class.''' from psyclone.psyir.nodes.node import colored, SCHEDULE_COLOUR_MAP return_stmt = Return() coloredtext = colored("Return", SCHEDULE_COLOUR_MAP["Return"]) assert coloredtext+"[]" in return_stmt.node_str()
def test_return_node_str(): ''' Check the node_str method of the Return class.''' return_stmt = Return() coloredtext = colored("Return", Return._colour) assert coloredtext + "[]" in return_stmt.node_str()
def test_return_can_be_printed(): '''Test that a Return instance can always be printed (i.e. is initialised fully)''' return_stmt = Return() assert "Return[]" in str(return_stmt)