def test_cw_array(): '''Check the CWriter class array method correctly prints out the C representation of an array. ''' cwriter = CWriter() assignment = Assignment() arr = Array('a', parent=assignment) lit = Literal('0.0', parent=assignment) assignment.addchild(arr) assignment.addchild(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) # Dimensions can be references, literals or operations arr.addchild(Reference('b', parent=arr)) arr.addchild(Literal('1', parent=arr)) uop = UnaryOperation(UnaryOperation.Operator.MINUS, parent=arr) uop.addchild(Literal('2', parent=uop)) 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, topology_name="", loop_type=""): Loop.__init__(self, parent=parent, valid_loop_types=["inner", "outer"]) self.loop_type = loop_type if self._loop_type == "inner": self._variable_name = "i" elif self._loop_type == "outer": self._variable_name = "j" # Pre-initialise the Loop children # TODO: See issue #440 self.addchild(Literal("NOT_INITIALISED", parent=self)) # start self.addchild(Literal("NOT_INITIALISED", parent=self)) # stop self.addchild(Literal("1", parent=self)) # step self.addchild(Schedule(parent=self)) # loop body
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": self._variable_name = "colour" elif self._loop_type == "colour": self._variable_name = "cell" else: self._variable_name = "cell" # Pre-initialise the Loop children # TODO: See issue #440 self.addchild(Literal("NOT_INITIALISED", parent=self)) # start self.addchild(Literal("NOT_INITIALISED", parent=self)) # stop self.addchild(Literal("1", parent=self)) # step self.addchild(Schedule(parent=self)) # loop body
def test_cw_literal(): '''Check the CWriter class literal method correctly prints out the C representation of a Literal. ''' cwriter = CWriter() lit = Literal('1') assert cwriter(lit) == '1' # Test that D scientific notation is replaced by 'e' lit = Literal("3e5", None) assert cwriter(lit) == '3e5' lit = Literal("3d5", None) assert cwriter(lit) == '3e5' lit = Literal("3D5", None) assert cwriter(lit) == '3e5' lit = Literal("3D+5", None) assert cwriter(lit) == '3e+5'
def test_fusetrans_error_not_same_parent(): ''' Check that we reject attempts to fuse loops which don't share the same parent ''' from psyclone.psyGen import Loop, Schedule, Literal from psyclone.transformations import LoopFuseTrans, TransformationError sch1 = Schedule() sch2 = Schedule() loop1 = Loop(variable_name="i", parent=sch1) loop2 = Loop(variable_name="j", parent=sch2) sch1.addchild(loop1) sch2.addchild(loop2) loop1.addchild(Literal("1", parent=loop1)) # start loop1.addchild(Literal("10", parent=loop1)) # stop loop1.addchild(Literal("1", parent=loop1)) # step loop1.addchild(Schedule(parent=loop1)) # loop body loop2.addchild(Literal("1", parent=loop2)) # start loop2.addchild(Literal("10", parent=loop2)) # stop loop2.addchild(Literal("1", parent=loop2)) # step loop2.addchild(Schedule(parent=loop2)) # loop body fuse = LoopFuseTrans() # Try to fuse loops with different parents with pytest.raises(TransformationError) as err: fuse.validate(loop1, loop2) assert "Error in LoopFuse transformation. Loops do not have the " \ "same parent" in str(err.value)
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", parent=self) if self._loop_type == "colours": self.stop_expr = Reference("ncolour", parent=self) elif self._loop_type == "colour": self.stop_expr = ArrayReference("ncp_ncolour", parent=self) self.stop_expr.addchild(Reference("colour"), parent=self.stop_expr) else: self.stop_expr = Reference(self.field_name + "%get_ncell()", parent=self) Loop.gen_code(self, parent)
def gen_code(self, parent): if self.field_space == "every": from psyclone.f2pygen import DeclGen from psyclone.psyGen import BinaryOperation, Reference dim_var = DeclGen(parent, datatype="INTEGER", entity_decls=[self._variable_name]) parent.add(dim_var) # Update start loop bound self.start_expr = Literal("1", parent=self) # Update stop loop bound if self._loop_type == "inner": index = "1" elif self._loop_type == "outer": index = "2" self.stop_expr = BinaryOperation(BinaryOperation.Operator.SIZE, parent=self) self.stop_expr.addchild(Reference(self.field_name, parent=self.stop_expr)) self.stop_expr.addchild(Literal(index, parent=self.stop_expr)) else: # one of our spaces so use values provided by the infrastructure # loop bounds # TODO: Issue 440. Implement derive types in PSyIR if self._loop_type == "inner": self.start_expr = Reference( self.field_space + "%istart", parent=self) self.stop_expr = Reference( self.field_space + "%istop", parent=self) elif self._loop_type == "outer": self.start_expr = Reference( self.field_space + "%jstart", parent=self) self.stop_expr = Reference( self.field_space + "%jstop", parent=self) Loop.gen_code(self, parent)
def gen_code(self, parent): if self.field_space == "every": from psyclone.f2pygen import DeclGen dim_var = DeclGen(parent, datatype="INTEGER", entity_decls=[self._variable_name]) parent.add(dim_var) # Update start loop bound self.start_expr = Literal("1", parent=self) # Update stop loop bound if self._loop_type == "inner": index = "1" elif self._loop_type == "outer": index = "2" # TODO: Issue 440. Implement SIZE intrinsic in PSyIR self.stop_expr = Literal("SIZE(" + self.field_name + "," + index + ")", parent=self) else: # one of our spaces so use values provided by the infrastructure # loop bounds # TODO: Issue 440. Implement derive types in PSyIR if self._loop_type == "inner": self.start_expr = Reference( self.field_space + "%istart", parent=self) self.stop_expr = Reference( self.field_space + "%istop", parent=self) elif self._loop_type == "outer": self.start_expr = Reference( self.field_space + "%jstart", parent=self) self.stop_expr = Reference( self.field_space + "%jstop", parent=self) Loop.gen_code(self, parent)
def test_cw_unaryoperator(): '''Check the CWriter class unary_operation method correctly prints out the C representation of any given UnaryOperation. ''' cwriter = CWriter() # Test UnaryOperation without children. unary_operation = UnaryOperation(UnaryOperation.Operator.MINUS) with pytest.raises(VisitorError) as err: _ = cwriter(unary_operation) assert("UnaryOperation malformed or incomplete. It should have " "exactly 1 child, but found 0." in str(err.value)) # Add child ref1 = Literal("a", unary_operation) unary_operation.addchild(ref1) assert cwriter(unary_operation) == '(-a)' # Test all supported Operators test_list = ((UnaryOperation.Operator.PLUS, '(+a)'), (UnaryOperation.Operator.MINUS, '(-a)'), (UnaryOperation.Operator.SQRT, 'sqrt(a)'), (UnaryOperation.Operator.NOT, '(!a)'), (UnaryOperation.Operator.COS, 'cos(a)'), (UnaryOperation.Operator.SIN, 'sin(a)'), (UnaryOperation.Operator.TAN, 'tan(a)'), (UnaryOperation.Operator.ACOS, 'acos(a)'), (UnaryOperation.Operator.ASIN, 'asin(a)'), (UnaryOperation.Operator.ATAN, 'atan(a)'), (UnaryOperation.Operator.ABS, 'abs(a)'), (UnaryOperation.Operator.REAL, 'float(a)')) for operator, expected in test_list: unary_operation._operator = operator assert cwriter(unary_operation) in expected # Test that an unsupported operator raises a error # pylint: disable=abstract-method, too-few-public-methods class Unsupported(): '''Dummy class''' # pylint: enable=abstract-method, too-few-public-methods unary_operation._operator = Unsupported with pytest.raises(NotImplementedError) as err: _ = cwriter(unary_operation) assert "The C backend does not support the '" in str(err) assert "' operator." in str(err)
def test_cw_size(): ''' Check the CWriter class SIZE method raises the expected error since there is no C equivalent. ''' cwriter = CWriter() assignment = Assignment() lhs = Reference('length', parent=assignment) size = BinaryOperation(BinaryOperation.Operator.SIZE, parent=assignment) assignment.addchild(lhs) assignment.addchild(size) arr = Array('a', parent=size) lit = Literal('1', parent=size) size.addchild(arr) size.addchild(lit) with pytest.raises(VisitorError) as excinfo: cwriter(assignment) assert ("C backend does not support the 'Operator.SIZE' operator" in str(excinfo.value))
def test_fusetrans_error_incomplete(): ''' Check that we reject attempts to fuse loops which are incomplete. ''' from psyclone.psyGen import Loop, Schedule, Literal, Return from psyclone.transformations import LoopFuseTrans, TransformationError sch = Schedule() loop1 = Loop(variable_name="i", parent=sch) loop2 = Loop(variable_name="j", 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 LoopFuse transformation. The first loop does not have " \ "4 children." in str(err.value) loop1.addchild(Literal("start", parent=loop1)) loop1.addchild(Literal("stop", parent=loop1)) loop1.addchild(Literal("step", 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 LoopFuse transformation. The second loop does not have " \ "4 children." in str(err.value) loop2.addchild(Literal("start", parent=loop2)) loop2.addchild(Literal("stop", parent=loop2)) loop2.addchild(Literal("step", parent=loop2)) loop2.addchild(Schedule(parent=loop2)) loop2.loop_body.addchild(Return(parent=loop2.loop_body)) # Validation should now pass fuse.validate(loop1, loop2)