예제 #1
0
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"
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
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'
예제 #5
0
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)
예제 #6
0
 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)
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
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)
예제 #10
0
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))
예제 #11
0
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)