Example #1
0
def test_ifblock_create_invalid():
    '''Test that the create method in an IfBlock class raises the expected
    exception if the provided input is invalid.

    '''
    if_condition = Literal('true', BOOLEAN_TYPE)
    if_body = [Assignment.create(
        Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
        Literal("0.0", REAL_SINGLE_TYPE)),
               Assignment.create(
                   Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                   Literal("1.0", REAL_SINGLE_TYPE))]

    # if_condition not a Node.
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create("True", if_body)
    assert ("Item 'str' can't be child 0 of 'If'. The valid format is: "
            "'DataNode, Schedule [, Schedule]'.") in str(excinfo.value)

    # One or more if body not a Node.
    if_body_err = [Assignment.create(Reference(DataSymbol("tmp",
                                                          REAL_SINGLE_TYPE)),
                                     Literal("0.0", REAL_SINGLE_TYPE)),
                   "invalid"]
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, if_body_err)
    assert ("Item 'str' can't be child 1 of 'Schedule'. The valid format is: "
            "'[Statement]*'.") in str(excinfo.value)

    # If body not a list.
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, "invalid")
    assert ("if_body argument in create method of IfBlock class should be a "
            "list.") in str(excinfo.value)

    # One of more of else_body not a Node.
    if_condition = Literal('true', BOOLEAN_TYPE)
    if_body = [Assignment.create(
        Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
        Literal("0.0", REAL_SINGLE_TYPE)),
               Assignment.create(
                   Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                   Literal("1.0", REAL_SINGLE_TYPE))]

    else_body_err = [Assignment.create(Reference(DataSymbol("tmp",
                                                            REAL_SINGLE_TYPE)),
                                       Literal("1.0", REAL_SINGLE_TYPE)),
                     "invalid"]
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, if_body, else_body_err)
    assert ("Item 'str' can't be child 1 of 'Schedule'. The valid format is: "
            "'[Statement]*'.") in str(excinfo.value)

    # Else body not a list.
    with pytest.raises(GenerationError) as excinfo:
        _ = IfBlock.create(if_condition, if_body, "invalid")
    assert ("else_body argument in create method of IfBlock class should be a "
            "list.") in str(excinfo.value)
Example #2
0
def test_ifblock_create():
    '''Test that the create method in an IfBlock class correctly creates
    an IfBlock instance.

    '''
    # Without an else clause.
    if_condition = Literal('true', BOOLEAN_TYPE)
    if_body = [Assignment.create(
        Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
        Literal("0.0", REAL_SINGLE_TYPE)),
               Assignment.create(
                   Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                   Literal("1.0", REAL_SINGLE_TYPE))]
    ifblock = IfBlock.create(if_condition, if_body)
    if_schedule = ifblock.children[1]
    assert isinstance(if_schedule, Schedule)
    check_links(ifblock, [if_condition, if_schedule])
    check_links(if_schedule, if_body)
    result = FortranWriter().ifblock_node(ifblock)
    assert result == ("if (.true.) then\n"
                      "  tmp = 0.0\n"
                      "  tmp2 = 1.0\n"
                      "end if\n")

    # With an else clause.
    if_condition = Literal('true', BOOLEAN_TYPE)
    if_body = [Assignment.create(
        Reference(DataSymbol("tmp", REAL_SINGLE_TYPE)),
        Literal("0.0", REAL_SINGLE_TYPE)),
               Assignment.create(
                   Reference(DataSymbol("tmp2", REAL_SINGLE_TYPE)),
                   Literal("1.0", REAL_SINGLE_TYPE))]
    else_body = [Assignment.create(Reference(DataSymbol("tmp",
                                                        REAL_SINGLE_TYPE)),
                                   Literal("1.0", REAL_SINGLE_TYPE)),
                 Assignment.create(Reference(DataSymbol("tmp2",
                                                        REAL_SINGLE_TYPE)),
                                   Literal("0.0", REAL_SINGLE_TYPE))]
    ifblock = IfBlock.create(if_condition, if_body, else_body)
    if_schedule = ifblock.children[1]
    assert isinstance(if_schedule, Schedule)
    else_schedule = ifblock.children[2]
    assert isinstance(else_schedule, Schedule)
    check_links(ifblock, [if_condition, if_schedule, else_schedule])
    check_links(if_schedule, if_body)
    check_links(else_schedule, else_body)
    result = FortranWriter().ifblock_node(ifblock)
    assert result == ("if (.true.) then\n"
                      "  tmp = 0.0\n"
                      "  tmp2 = 1.0\n"
                      "else\n"
                      "  tmp = 1.0\n"
                      "  tmp2 = 0.0\n"
                      "end if\n")
Example #3
0
def test_ifblock_invalid_annotation():
    ''' Test that initialising IfBlock with invalid annotations produce the
    expected error.'''

    with pytest.raises(InternalError) as err:
        _ = IfBlock(annotations=["invalid"])
    assert ("IfBlock with unrecognized annotation 'invalid', valid "
            "annotations are:") in str(err.value)
Example #4
0
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
Example #5
0
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
Example #6
0
def test_ifblock_node_str():
    ''' Check the node_str method of the IfBlock class.'''
    colouredif = colored("If", IfBlock._colour)

    ifblock = IfBlock()
    output = ifblock.node_str()
    assert colouredif+"[]" in output

    ifblock = IfBlock(annotations=['was_elseif'])
    output = ifblock.node_str()
    assert colouredif+"[annotations='was_elseif']" in output
Example #7
0
def test_ifblock_node_str():
    ''' Check the node_str method of the IfBlock class.'''
    from psyclone.psyir.nodes.node import colored, SCHEDULE_COLOUR_MAP
    colouredif = colored("If", SCHEDULE_COLOUR_MAP["If"])

    ifblock = IfBlock()
    output = ifblock.node_str()
    assert colouredif + "[]" in output

    ifblock = IfBlock(annotations=['was_elseif'])
    output = ifblock.node_str()
    assert colouredif + "[annotations='was_elseif']" in output
Example #8
0
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")
Example #9
0
def test_ifblock_children_region():
    ''' Check that we reject attempts to transform the conditional part of
    an If statement or to include both the if- and else-clauses in a region
    (without their parent). '''
    acct = ACCParallelTrans()
    # Construct a valid IfBlock
    condition = Reference(DataSymbol('condition', BOOLEAN_TYPE))
    ifblock = IfBlock.create(condition, [], [])

    # Attempt to put all of the children of the IfBlock into a region. This
    # is an error because the first child is the conditional part of the
    # IfBlock.
    with pytest.raises(TransformationError) as err:
        super(ACCParallelTrans, acct).validate([ifblock.children[0]])
    assert ("transformation to the immediate children of a Loop/IfBlock "
            "unless it is to a single Schedule" in str(err.value))
    with pytest.raises(TransformationError) as err:
        super(ACCParallelTrans, acct).validate(ifblock.children[1:])
    assert (" to multiple nodes when one or more is a Schedule. "
            "Either target a single Schedule or " in str(err.value))
Example #10
0
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
Example #11
0
    def apply(self, node, options=None):
        '''Apply the MIN intrinsic conversion transformation to the specified
        node. This node must be an MIN NaryOperation. The MIN
        NaryOperation is converted to equivalent inline code.  This is
        implemented as a PSyIR transform from:

        .. code-block:: python

            R = ... MIN(A, B, C ...) ...

        to:

        .. code-block:: python

            res_min = A
            tmp_min = B
            IF tmp_min < res_min:
                res_min = tmp_min
            tmp_min = C
            IF tmp_min < res_min:
                res_min = tmp_min
            ...
            R = ... res_min ...

        where ``A``, ``B``, ``C`` ... could be arbitrarily complex PSyIR
        expressions and the ``...`` before and after ``MIN(A, B, C
        ...)`` can be arbitrary PSyIR code.

        This transformation requires the operation node to be a
        descendent of an assignment and will raise an exception if
        this is not the case.

        :param node: a MIN Binary- or Nary-Operation node.
        :type node: :py:class:`psyclone.psyGen.BinaryOperation` or \
        :py:class:`psyclone.psyGen.NaryOperation`
        :param symbol_table: the symbol table.
        :type symbol_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
        :param options: a dictionary with options for transformations.
        :type options: dictionary of string:values or None

        '''
        # pylint: disable=too-many-locals
        self.validate(node)

        schedule = node.root
        symbol_table = schedule.symbol_table

        oper_parent = node.parent
        assignment = node.ancestor(Assignment)

        # Create a temporary result variable. There is an assumption
        # here that the MIN Operator returns a PSyIR real type. This
        # might not be what is wanted (e.g. the args might PSyIR
        # integers), or there may be errors (arguments are of
        # different types) but this can't be checked as we don't have
        # appropriate methods to query nodes (see #658).
        res_var_symbol = symbol_table.new_symbol(
            "res_min", symbol_type=DataSymbol, datatype=REAL_TYPE)
        # Create a temporary variable. Again there is an
        # assumption here about the datatype - please see previous
        # comment (associated issue #658).
        tmp_var_symbol = symbol_table.new_symbol(
            "tmp_min", symbol_type=DataSymbol, datatype=REAL_TYPE)

        # Replace operation with a temporary (res_var).
        oper_parent.children[node.position] = Reference(res_var_symbol,
                                                        parent=oper_parent)

        # res_var=A
        lhs = Reference(res_var_symbol)
        new_assignment = Assignment.create(lhs, node.children[0])
        new_assignment.parent = assignment.parent
        assignment.parent.children.insert(assignment.position, new_assignment)

        # For each of the remaining min arguments (B,C...)
        for expression in node.children[1:]:

            # tmp_var=(B or C or ...)
            lhs = Reference(tmp_var_symbol)
            new_assignment = Assignment.create(lhs, expression)
            new_assignment.parent = assignment.parent
            assignment.parent.children.insert(assignment.position,
                                              new_assignment)

            # if_condition: tmp_var<res_var
            lhs = Reference(tmp_var_symbol)
            rhs = Reference(res_var_symbol)
            if_condition = BinaryOperation.create(BinaryOperation.Operator.LT,
                                                  lhs, rhs)

            # then_body: res_var=tmp_var
            lhs = Reference(res_var_symbol)
            rhs = Reference(tmp_var_symbol)
            then_body = [Assignment.create(lhs, rhs)]

            # if [if_condition] then [then_body]
            if_stmt = IfBlock.create(if_condition, then_body)
            if_stmt.parent = assignment.parent
            assignment.parent.children.insert(assignment.position, if_stmt)
Example #12
0
def test_ifblock_children_validation():
    '''Test that children added to IfBlock are validated. IfBlock accepts
    DataNodes for the children 0 to 2 and a Shcedule for child 3.

    '''
    ifblock = IfBlock()
    if_condition = Literal('true', BOOLEAN_TYPE)
    if_body = Schedule()
    else_body = Schedule()

    # First child
    with pytest.raises(GenerationError) as excinfo:
        ifblock.addchild(if_body)
    assert ("Item 'Schedule' can't be child 0 of 'If'. The valid format is: "
            "'DataNode, Schedule [, Schedule]'." in str(excinfo.value))
    ifblock.addchild(if_condition)

    # Second child
    with pytest.raises(GenerationError) as excinfo:
        ifblock.addchild(if_condition)
    assert ("Item 'Literal' can't be child 1 of 'If'. The valid format is: "
            "'DataNode, Schedule [, Schedule]'." in str(excinfo.value))
    ifblock.addchild(if_body)

    # Third child
    with pytest.raises(GenerationError) as excinfo:
        ifblock.addchild(if_condition)
    assert ("Item 'Literal' can't be child 2 of 'If'. The valid format is: "
            "'DataNode, Schedule [, Schedule]'." in str(excinfo.value))
    ifblock.addchild(else_body)

    # Additional children
    with pytest.raises(GenerationError) as excinfo:
        ifblock.addchild(else_body)
    assert ("Item 'Schedule' can't be child 3 of 'If'. The valid format is: "
            "'DataNode, Schedule [, Schedule]'." in str(excinfo.value))
    def apply(self, node, options=None):
        '''Apply this transformation to the supplied node.

        :param node: the node to transform.
        :type node: :py:class:`psyclone.gocean1p0.GOKern`
        :param options: a dictionary with options for transformations.
        :type options: dict of string:values or None

        :returns: 2-tuple of new schedule and memento of transform.
        :rtype: (:py:class:`psyclone.gocean1p0.GOInvokeSchedule`, \
                 :py:class:`psyclone.undoredo.Memento`)

        '''
        self.validate(node, options)

        # Get useful references
        invoke_st = node.ancestor(InvokeSchedule).symbol_table
        inner_loop = node.ancestor(Loop)
        outer_loop = inner_loop.ancestor(Loop)
        cursor = outer_loop.position

        # Make sure the boundary symbols in the PSylayer exist
        inv_xstart = invoke_st.symbol_from_tag("xstart_" + node.name,
                                               root_name="xstart",
                                               symbol_type=DataSymbol,
                                               datatype=INTEGER_TYPE)
        inv_xstop = invoke_st.symbol_from_tag("xstop_" + node.name,
                                              root_name="xstop",
                                              symbol_type=DataSymbol,
                                              datatype=INTEGER_TYPE)
        inv_ystart = invoke_st.symbol_from_tag("ystart_" + node.name,
                                               root_name="ystart",
                                               symbol_type=DataSymbol,
                                               datatype=INTEGER_TYPE)
        inv_ystop = invoke_st.symbol_from_tag("ystop_" + node.name,
                                              root_name="ystop",
                                              symbol_type=DataSymbol,
                                              datatype=INTEGER_TYPE)

        # If the kernel acts on the whole iteration space, the boundary values
        # are not needed. This also avoids adding duplicated arguments if this
        # transformation is applied more than once to the same kernel. But the
        # declaration and initialisation above still needs to exist because the
        # boundary variables are expected to exist by the generation code.
        if (inner_loop.field_space == "go_every"
                and outer_loop.field_space == "go_every"
                and inner_loop.iteration_space == "go_all_pts"
                and outer_loop.iteration_space == "go_all_pts"):
            return node.root, None

        # Initialise the boundary values provided by the Loop construct
        assign1 = Assignment.create(Reference(inv_xstart),
                                    inner_loop.lower_bound().copy())
        outer_loop.parent.children.insert(cursor, assign1)
        cursor = cursor + 1
        assign2 = Assignment.create(Reference(inv_xstop),
                                    inner_loop.upper_bound().copy())
        outer_loop.parent.children.insert(cursor, assign2)
        cursor = cursor + 1
        assign3 = Assignment.create(Reference(inv_ystart),
                                    outer_loop.lower_bound().copy())
        outer_loop.parent.children.insert(cursor, assign3)
        cursor = cursor + 1
        assign4 = Assignment.create(Reference(inv_ystop),
                                    outer_loop.upper_bound().copy())
        outer_loop.parent.children.insert(cursor, assign4)

        # Update Kernel Call argument list
        for symbol in [inv_xstart, inv_xstop, inv_ystart, inv_ystop]:
            node.arguments.append(symbol.name, "go_i_scalar")

        # Now that the boundaries are inside the kernel, the looping should go
        # through all the field points
        inner_loop.field_space = "go_every"
        outer_loop.field_space = "go_every"
        inner_loop.iteration_space = "go_all_pts"
        outer_loop.iteration_space = "go_all_pts"

        # Update Kernel
        kschedule = node.get_kernel_schedule()
        kernel_st = kschedule.symbol_table
        iteration_indices = kernel_st.iteration_indices
        data_arguments = kernel_st.data_arguments

        # Create new symbols and insert them as kernel arguments at the end of
        # the kernel argument list
        xstart_symbol = kernel_st.new_symbol(
            "xstart",
            symbol_type=DataSymbol,
            datatype=INTEGER_TYPE,
            interface=ArgumentInterface(ArgumentInterface.Access.READ))
        xstop_symbol = kernel_st.new_symbol("xstop",
                                            symbol_type=DataSymbol,
                                            datatype=INTEGER_TYPE,
                                            interface=ArgumentInterface(
                                                ArgumentInterface.Access.READ))
        ystart_symbol = kernel_st.new_symbol(
            "ystart",
            symbol_type=DataSymbol,
            datatype=INTEGER_TYPE,
            interface=ArgumentInterface(ArgumentInterface.Access.READ))
        ystop_symbol = kernel_st.new_symbol("ystop",
                                            symbol_type=DataSymbol,
                                            datatype=INTEGER_TYPE,
                                            interface=ArgumentInterface(
                                                ArgumentInterface.Access.READ))
        kernel_st.specify_argument_list(
            iteration_indices + data_arguments +
            [xstart_symbol, xstop_symbol, ystart_symbol, ystop_symbol])

        # Create boundary masking conditions
        condition1 = BinaryOperation.create(BinaryOperation.Operator.LT,
                                            Reference(iteration_indices[0]),
                                            Reference(xstart_symbol))
        condition2 = BinaryOperation.create(BinaryOperation.Operator.GT,
                                            Reference(iteration_indices[0]),
                                            Reference(xstop_symbol))
        condition3 = BinaryOperation.create(BinaryOperation.Operator.LT,
                                            Reference(iteration_indices[1]),
                                            Reference(ystart_symbol))
        condition4 = BinaryOperation.create(BinaryOperation.Operator.GT,
                                            Reference(iteration_indices[1]),
                                            Reference(ystop_symbol))

        condition = BinaryOperation.create(
            BinaryOperation.Operator.OR,
            BinaryOperation.create(BinaryOperation.Operator.OR, condition1,
                                   condition2),
            BinaryOperation.create(BinaryOperation.Operator.OR, condition3,
                                   condition4))

        # Insert the conditional mask as the first statement of the kernel
        if_statement = IfBlock.create(condition, [Return()])
        kschedule.children.insert(0, if_statement)

        return node.root, None
Example #14
0
    def apply(self, node, options=None):
        '''Apply the SIGN intrinsic conversion transformation to the specified
        node. This node must be a SIGN BinaryOperation. The SIGN
        BinaryOperation is converted to equivalent inline code. This
        is implemented as a PSyIR transform from:

        .. code-block:: python

            R = ... SIGN(A, B) ...

        to:

        .. code-block:: python

            tmp_abs = A
            if tmp_abs < 0.0:
                res_abs = tmp_abs*-1.0
            else:
                res_abs = tmp_abs
            res_sign = res_abs
            tmp_sign = B
            if tmp_sign < 0.0:
                res_sign = res_sign*-1.0
            R = ... res_sign ...

        where ``A`` and ``B`` could be arbitrarily complex PSyIR
        expressions, ``...`` could be arbitrary PSyIR code and where
        ``ABS`` has been replaced with inline code by the NemoAbsTrans
        transformation.

        This transformation requires the operation node to be a
        descendent of an assignment and will raise an exception if
        this is not the case.

        :param node: a SIGN BinaryOperation node.
        :type node: :py:class:`psyclone.psyGen.BinaryOperation`
        :param symbol_table: the symbol table.
        :type symbol_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
        :param options: a dictionary with options for transformations.
        :type options: dictionary of string:values or None

        '''
        # pylint: disable=too-many-locals
        self.validate(node)

        schedule = node.root
        symbol_table = schedule.symbol_table

        oper_parent = node.parent
        assignment = node.ancestor(Assignment)
        # Create two temporary variables.  There is an assumption here
        # that the SIGN Operator returns a PSyIR real type. This might
        # not be what is wanted (e.g. the args might PSyIR integers),
        # or there may be errors (arguments are of different types)
        # but this can't be checked as we don't have the appropriate
        # methods to query nodes (see #658).
        res_var_symbol = symbol_table.new_symbol("res_sign",
                                                 symbol_type=DataSymbol,
                                                 datatype=REAL_TYPE)
        tmp_var_symbol = symbol_table.new_symbol("tmp_sign",
                                                 symbol_type=DataSymbol,
                                                 datatype=REAL_TYPE)

        # Replace operator with a temporary (res_var).
        oper_parent.children[node.position] = Reference(res_var_symbol,
                                                        parent=oper_parent)

        # Extract the operand nodes
        op1, op2 = node.pop_all_children()

        # res_var=ABS(A)
        lhs = Reference(res_var_symbol)
        rhs = UnaryOperation.create(UnaryOperation.Operator.ABS, op1)
        new_assignment = Assignment.create(lhs, rhs)
        assignment.parent.children.insert(assignment.position, new_assignment)

        # Replace the ABS intrinsic with inline code.
        abs_trans = Abs2CodeTrans()
        abs_trans.apply(rhs, symbol_table)

        # tmp_var=B
        lhs = Reference(tmp_var_symbol)
        new_assignment = Assignment.create(lhs, op2)
        assignment.parent.children.insert(assignment.position, new_assignment)

        # if_condition: tmp_var<0.0
        lhs = Reference(tmp_var_symbol)
        rhs = Literal("0.0", REAL_TYPE)
        if_condition = BinaryOperation.create(BinaryOperation.Operator.LT, lhs,
                                              rhs)

        # then_body: res_var=res_var*-1.0
        lhs = Reference(res_var_symbol)
        lhs_child = Reference(res_var_symbol)
        rhs_child = Literal("-1.0", REAL_TYPE)
        rhs = BinaryOperation.create(BinaryOperation.Operator.MUL, lhs_child,
                                     rhs_child)
        then_body = [Assignment.create(lhs, rhs)]

        # if [if_condition] then [then_body]
        if_stmt = IfBlock.create(if_condition, then_body)
        assignment.parent.children.insert(assignment.position, if_stmt)
Example #15
0
TMPARRAY = Array.create(ARRAY, [MY_RANGE])

# Assignments
ASSIGN1 = Assignment.create(TMP1, ZERO)
ASSIGN2 = Assignment.create(TMP2, ZERO)
ASSIGN3 = Assignment.create(TMP2, BINARYOPERATION)
ASSIGN4 = Assignment.create(TMP1, TMP2)
ASSIGN5 = Assignment.create(TMP1, NARYOPERATION)
ASSIGN6 = Assignment.create(TMPARRAY, TWO)

# Call
CALL = Call.create(ROUTINE_SYMBOL, [TMP1, BINARYOPERATION])

# If statement
IF_CONDITION = BinaryOperation.create(BinaryOperation.Operator.GT, TMP1, ZERO)
IFBLOCK = IfBlock.create(IF_CONDITION, [ASSIGN3, ASSIGN4])

# Loop
LOOP = Loop.create(INDEX_SYMBOL, INT_ZERO, INT_ONE, INT_ONE, [IFBLOCK])

# KernelSchedule
KERNEL_SCHEDULE = KernelSchedule.create(
    "work", SYMBOL_TABLE, [CALL, ASSIGN2, LOOP, ASSIGN5, ASSIGN6])

# Container
CONTAINER_SYMBOL_TABLE = SymbolTable()
CONTAINER = Container.create("CONTAINER", CONTAINER_SYMBOL_TABLE,
                             [KERNEL_SCHEDULE])

# Import data from another container
EXTERNAL_CONTAINER = ContainerSymbol("some_mod")
Example #16
0
def create_psyir_tree():
    ''' Create an example PSyIR Tree.

    :returns: an example PSyIR tree.
    :rtype: :py:class:`psyclone.psyir.nodes.Container`

    '''
    # Symbol table, symbols and scalar datatypes
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    symbol_table.specify_argument_list([arg1])
    tmp_symbol = symbol_table.new_symbol(symbol_type=DataSymbol,
                                         datatype=REAL_DOUBLE_TYPE)
    index_symbol = symbol_table.new_symbol(root_name="i",
                                           symbol_type=DataSymbol,
                                           datatype=INTEGER4_TYPE)
    real_kind = symbol_table.new_symbol(root_name="RKIND",
                                        symbol_type=DataSymbol,
                                        datatype=INTEGER_TYPE,
                                        constant_value=8)
    routine_symbol = RoutineSymbol("my_sub")

    # Array using precision defined by another symbol
    scalar_type = ScalarType(ScalarType.Intrinsic.REAL, real_kind)
    array = symbol_table.new_symbol(root_name="a",
                                    symbol_type=DataSymbol,
                                    datatype=ArrayType(scalar_type, [10]))

    # Make generators for nodes which do not have other Nodes as children,
    # with some predefined scalar datatypes
    def zero():
        return Literal("0.0", REAL_TYPE)

    def one():
        return Literal("1.0", REAL4_TYPE)

    def two():
        return Literal("2.0", scalar_type)

    def int_zero():
        return Literal("0", INTEGER_SINGLE_TYPE)

    def int_one():
        return Literal("1", INTEGER8_TYPE)

    def tmp1():
        return Reference(arg1)

    def tmp2():
        return Reference(tmp_symbol)

    # Unary Operation
    oper = UnaryOperation.Operator.SIN
    unaryoperation = UnaryOperation.create(oper, tmp2())

    # Binary Operation
    oper = BinaryOperation.Operator.ADD
    binaryoperation = BinaryOperation.create(oper, one(), unaryoperation)

    # Nary Operation
    oper = NaryOperation.Operator.MAX
    naryoperation = NaryOperation.create(oper, [tmp1(), tmp2(), one()])

    # Array reference using a range
    lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                    Reference(array), int_one())
    ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                    Reference(array), int_one())
    my_range = Range.create(lbound, ubound)
    tmparray = ArrayReference.create(array, [my_range])

    # Assignments
    assign1 = Assignment.create(tmp1(), zero())
    assign2 = Assignment.create(tmp2(), zero())
    assign3 = Assignment.create(tmp2(), binaryoperation)
    assign4 = Assignment.create(tmp1(), tmp2())
    assign5 = Assignment.create(tmp1(), naryoperation)
    assign6 = Assignment.create(tmparray, two())

    # Call
    call = Call.create(routine_symbol, [tmp1(), binaryoperation.copy()])

    # If statement
    if_condition = BinaryOperation.create(BinaryOperation.Operator.GT, tmp1(),
                                          zero())
    ifblock = IfBlock.create(if_condition, [assign3, assign4])

    # Loop
    loop = Loop.create(index_symbol, int_zero(), int_one(), int_one(),
                       [ifblock])

    # KernelSchedule
    kernel_schedule = KernelSchedule.create(
        "work", symbol_table, [assign1, call, assign2, loop, assign5, assign6])

    # Container
    container_symbol_table = SymbolTable()
    container = Container.create("CONTAINER", container_symbol_table,
                                 [kernel_schedule])

    # Import data from another container
    external_container = ContainerSymbol("some_mod")
    container_symbol_table.add(external_container)
    external_var = DataSymbol("some_var",
                              INTEGER_TYPE,
                              interface=GlobalInterface(external_container))
    container_symbol_table.add(external_var)
    routine_symbol.interface = GlobalInterface(external_container)
    container_symbol_table.add(routine_symbol)
    return container
Example #17
0
    def apply(self, node, options=None):
        '''Apply the ABS intrinsic conversion transformation to the specified
        node. This node must be an ABS UnaryOperation. The ABS
        UnaryOperation is converted to equivalent inline code. This is
        implemented as a PSyIR transform from:

        .. code-block:: python

            R = ... ABS(X) ...

        to:

        .. code-block:: python

            tmp_abs = X
            if tmp_abs < 0.0:
                res_abs = tmp_abs*-1.0
            else:
                res_abs = tmp_abs
            R = ... res_abs ...

        where ``X`` could be an arbitrarily complex PSyIR expression
        and ``...`` could be arbitrary PSyIR code.

        This transformation requires the operation node to be a
        descendent of an assignment and will raise an exception if
        this is not the case.

        :param node: an ABS UnaryOperation node.
        :type node: :py:class:`psyclone.psyGen.UnaryOperation`
        :param options: a dictionary with options for transformations.
        :type options: dictionary of string:values or None

        '''
        # pylint: disable=too-many-locals
        self.validate(node)

        schedule = node.root
        symbol_table = schedule.symbol_table

        oper_parent = node.parent
        assignment = node.ancestor(Assignment)
        # Create two temporary variables.  There is an assumption here
        # that the ABS Operator returns a PSyIR real type. This might
        # not be what is wanted (e.g. the args might PSyIR integers),
        # or there may be errors (arguments are of different types)
        # but this can't be checked as we don't have the appropriate
        # methods to query nodes (see #658).
        symbol_res_var = symbol_table.new_symbol("res_abs",
                                                 symbol_type=DataSymbol,
                                                 datatype=REAL_TYPE)
        symbol_tmp_var = symbol_table.new_symbol("tmp_abs",
                                                 symbol_type=DataSymbol,
                                                 datatype=REAL_TYPE)

        # Replace operation with a temporary (res_X).
        oper_parent.children[node.position] = Reference(symbol_res_var,
                                                        parent=oper_parent)

        # tmp_var=X
        lhs = Reference(symbol_tmp_var)
        rhs = node.children[0]
        new_assignment = Assignment.create(lhs, rhs)
        new_assignment.parent = assignment.parent
        assignment.parent.children.insert(assignment.position, new_assignment)

        # if condition: tmp_var>0.0
        lhs = Reference(symbol_tmp_var)
        rhs = Literal("0.0", REAL_TYPE)
        if_condition = BinaryOperation.create(BinaryOperation.Operator.GT, lhs,
                                              rhs)

        # then_body: res_var=tmp_var
        lhs = Reference(symbol_res_var)
        rhs = Reference(symbol_tmp_var)
        then_body = [Assignment.create(lhs, rhs)]

        # else_body: res_var=-1.0*tmp_var
        lhs = Reference(symbol_res_var)
        lhs_child = Reference(symbol_tmp_var)
        rhs_child = Literal("-1.0", REAL_TYPE)
        rhs = BinaryOperation.create(BinaryOperation.Operator.MUL, lhs_child,
                                     rhs_child)
        else_body = [Assignment.create(lhs, rhs)]

        # if [if_condition] then [then_body] else [else_body]
        if_stmt = IfBlock.create(if_condition, then_body, else_body)
        if_stmt.parent = assignment.parent
        assignment.parent.children.insert(assignment.position, if_stmt)
Example #18
0
def create_psyir_tree():
    ''' Create an example PSyIR Tree.

    :returns: an example PSyIR tree.
    :rtype: :py:class:`psyclone.psyir.nodes.Container`

    '''
    # Symbol table, symbols and scalar datatypes
    symbol_table = SymbolTable()
    arg1 = symbol_table.new_symbol(symbol_type=DataSymbol,
                                   datatype=REAL_TYPE,
                                   interface=ArgumentInterface(
                                       ArgumentInterface.Access.READWRITE))
    symbol_table.specify_argument_list([arg1])
    tmp_symbol = symbol_table.new_symbol(symbol_type=DataSymbol,
                                         datatype=REAL_DOUBLE_TYPE)
    index_symbol = symbol_table.new_symbol(root_name="i",
                                           symbol_type=DataSymbol,
                                           datatype=INTEGER4_TYPE)
    real_kind = symbol_table.new_symbol(root_name="RKIND",
                                        symbol_type=DataSymbol,
                                        datatype=INTEGER_TYPE,
                                        constant_value=8)
    routine_symbol = RoutineSymbol("my_sub")

    # Array using precision defined by another symbol
    scalar_type = ScalarType(ScalarType.Intrinsic.REAL, real_kind)
    array = symbol_table.new_symbol(root_name="a",
                                    symbol_type=DataSymbol,
                                    datatype=ArrayType(scalar_type, [10]))

    # Nodes which do not have Nodes as children and (some) predefined
    # scalar datatypes
    # TODO: Issue #1136 looks at how to avoid all of the _x versions
    zero_1 = Literal("0.0", REAL_TYPE)
    zero_2 = Literal("0.0", REAL_TYPE)
    zero_3 = Literal("0.0", REAL_TYPE)
    one_1 = Literal("1.0", REAL4_TYPE)
    one_2 = Literal("1.0", REAL4_TYPE)
    one_3 = Literal("1.0", REAL4_TYPE)
    two = Literal("2.0", scalar_type)
    int_zero = Literal("0", INTEGER_SINGLE_TYPE)
    int_one_1 = Literal("1", INTEGER8_TYPE)
    int_one_2 = Literal("1", INTEGER8_TYPE)
    int_one_3 = Literal("1", INTEGER8_TYPE)
    int_one_4 = Literal("1", INTEGER8_TYPE)
    tmp1_1 = Reference(arg1)
    tmp1_2 = Reference(arg1)
    tmp1_3 = Reference(arg1)
    tmp1_4 = Reference(arg1)
    tmp1_5 = Reference(arg1)
    tmp1_6 = Reference(arg1)
    tmp2_1 = Reference(tmp_symbol)
    tmp2_2 = Reference(tmp_symbol)
    tmp2_3 = Reference(tmp_symbol)
    tmp2_4 = Reference(tmp_symbol)
    tmp2_5 = Reference(tmp_symbol)
    tmp2_6 = Reference(tmp_symbol)

    # Unary Operation
    oper = UnaryOperation.Operator.SIN
    unaryoperation_1 = UnaryOperation.create(oper, tmp2_1)
    unaryoperation_2 = UnaryOperation.create(oper, tmp2_2)

    # Binary Operation
    oper = BinaryOperation.Operator.ADD
    binaryoperation_1 = BinaryOperation.create(oper, one_1, unaryoperation_1)
    binaryoperation_2 = BinaryOperation.create(oper, one_2, unaryoperation_2)

    # Nary Operation
    oper = NaryOperation.Operator.MAX
    naryoperation = NaryOperation.create(oper, [tmp1_1, tmp2_3, one_3])

    # Array reference using a range
    lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND,
                                    Reference(array), int_one_1)
    ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND,
                                    Reference(array), int_one_2)
    my_range = Range.create(lbound, ubound)
    tmparray = ArrayReference.create(array, [my_range])

    # Assignments
    assign1 = Assignment.create(tmp1_2, zero_1)
    assign2 = Assignment.create(tmp2_4, zero_2)
    assign3 = Assignment.create(tmp2_5, binaryoperation_1)
    assign4 = Assignment.create(tmp1_3, tmp2_6)
    assign5 = Assignment.create(tmp1_4, naryoperation)
    assign6 = Assignment.create(tmparray, two)

    # Call
    call = Call.create(routine_symbol, [tmp1_5, binaryoperation_2])

    # If statement
    if_condition = BinaryOperation.create(BinaryOperation.Operator.GT, tmp1_6,
                                          zero_3)
    ifblock = IfBlock.create(if_condition, [assign3, assign4])

    # Loop
    loop = Loop.create(index_symbol, int_zero, int_one_3, int_one_4, [ifblock])

    # KernelSchedule
    kernel_schedule = KernelSchedule.create(
        "work", symbol_table, [assign1, call, assign2, loop, assign5, assign6])

    # Container
    container_symbol_table = SymbolTable()
    container = Container.create("CONTAINER", container_symbol_table,
                                 [kernel_schedule])

    # Import data from another container
    external_container = ContainerSymbol("some_mod")
    container_symbol_table.add(external_container)
    external_var = DataSymbol("some_var",
                              INTEGER_TYPE,
                              interface=GlobalInterface(external_container))
    container_symbol_table.add(external_var)
    routine_symbol.interface = GlobalInterface(external_container)
    container_symbol_table.add(routine_symbol)
    return container