示例#1
0
def test_invalid():
    '''Check that the validate tests are run when the apply method is
    called.'''
    trans = Sign2CodeTrans()
    with pytest.raises(TransformationError) as excinfo:
        trans.apply(None)
    assert (
        "Error in Sign2CodeTrans transformation. The supplied node argument "
        "is not a SIGN operator, found 'NoneType'." in str(excinfo.value))
示例#2
0
def trans(psy):
    '''Transformation routine for use with PSyclone. Applies the PSyIR2SIR
    transform to the supplied invokes after replacing any ABS, SIGN or
    MIN intrinsics with equivalent code. This is done because the SIR
    does not support intrinsics.

    :param psy: the PSy object which this script will transform.
    :type psy: :py:class:`psyclone.psyGen.PSy`
    :returns: the transformed PSy object.
    :rtype: :py:class:`psyclone.psyGen.PSy`

    '''
    abs_trans = Abs2CodeTrans()
    sign_trans = Sign2CodeTrans()
    min_trans = Min2CodeTrans()
    nemo_loop_trans = NemoAllArrayRange2LoopTrans()

    sir_writer = SIRWriter()
    fortran_writer = FortranWriter()

    # For each Invoke write out the SIR representation of the
    # schedule. Note, there is no algorithm layer in the NEMO API so
    # the invokes represent all of the original code.
    for invoke in psy.invokes.invoke_list:
        schedule = invoke.schedule
        for assignment in schedule.walk(Assignment):
            nemo_loop_trans.apply(assignment)

        for kernel in schedule.walk(NemoKern):

            # The NEMO api currently has no symbol table so create one
            # to allow the generation of new variables. Note, this
            # does not guarantee unique names as we don't know any of
            # the existing names (so generated names could clash).
            symbol_table = SymbolTable()

            kernel_schedule = kernel.get_kernel_schedule()
            for oper in kernel_schedule.walk(Operation):
                if oper.operator == UnaryOperation.Operator.ABS:
                    # Apply ABS transformation
                    abs_trans.apply(oper, symbol_table)
                elif oper.operator == BinaryOperation.Operator.SIGN:
                    # Apply SIGN transformation
                    sign_trans.apply(oper, symbol_table)
                elif oper.operator in [
                        BinaryOperation.Operator.MIN,
                        NaryOperation.Operator.MIN
                ]:
                    # Apply (2-n arg) MIN transformation
                    min_trans.apply(oper, symbol_table)
        kern = fortran_writer(schedule)
        print(kern)
        kern = sir_writer(schedule)
        print(kern)

    return psy
示例#3
0
def test_initialise():
    '''Check that variables are set up as expected when an instance of the
    class is created and that the str and name methods work as expected.

    '''
    trans = Sign2CodeTrans()
    assert trans._operator_name == "SIGN"
    assert trans._classes == (BinaryOperation, )
    assert trans._operators == (BinaryOperation.Operator.SIGN, )
    assert (str(trans) == "Convert the PSyIR SIGN intrinsic to equivalent "
            "PSyIR code.")
    assert trans.name == "Sign2CodeTrans"
示例#4
0
def test_correct_expr(tmpdir):
    '''Check that a valid example produces the expected output when SIGN
    is part of an expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir(lambda arg: BinaryOperation.create(
        BinaryOperation.Operator.MUL, arg, Literal("3.14", REAL_TYPE)))
    root = operation.root
    assignment = operation.parent
    operation.detach()
    op1 = BinaryOperation.create(BinaryOperation.Operator.ADD,
                                 Literal("1.0", REAL_TYPE), operation)
    op2 = BinaryOperation.create(BinaryOperation.Operator.ADD, op1,
                                 Literal("2.0", REAL_TYPE))
    assignment.addchild(op2)
    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine sign_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp = 1.0 + SIGN(arg * 3.14, arg_1) + 2.0\n\n"
            "end subroutine sign_example\n") in result
    trans = Sign2CodeTrans()
    trans.apply(operation, root.symbol_table)
    result = writer(root)
    assert ("subroutine sign_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_sign\n"
            "  real :: tmp_sign\n"
            "  real :: res_abs\n"
            "  real :: tmp_abs\n\n"
            "  tmp_abs = arg * 3.14\n"
            "  if (tmp_abs > 0.0) then\n"
            "    res_abs = tmp_abs\n"
            "  else\n"
            "    res_abs = tmp_abs * -1.0\n"
            "  end if\n"
            "  res_sign = res_abs\n"
            "  tmp_sign = arg_1\n"
            "  if (tmp_sign < 0.0) then\n"
            "    res_sign = res_sign * -1.0\n"
            "  end if\n"
            "  psyir_tmp = 1.0 + res_sign + 2.0\n\n"
            "end subroutine sign_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
示例#5
0
def test_correct(func, output, tmpdir):
    '''Check that a valid example produces the expected output when the
    first argument to SIGN is a simple argument and when it is an
    expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir(func)
    root = operation.root
    writer = FortranWriter()
    result = writer(root)
    assert ("subroutine sign_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp = SIGN({0}, arg_1)\n\n"
            "end subroutine sign_example\n".format(output)) in result
    trans = Sign2CodeTrans()
    trans.apply(operation, root.symbol_table)
    result = writer(root)
    assert ("subroutine sign_example(arg, arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_sign\n"
            "  real :: tmp_sign\n"
            "  real :: res_abs\n"
            "  real :: tmp_abs\n\n"
            "  tmp_abs = {0}\n"
            "  if (tmp_abs > 0.0) then\n"
            "    res_abs = tmp_abs\n"
            "  else\n"
            "    res_abs = tmp_abs * -1.0\n"
            "  end if\n"
            "  res_sign = res_abs\n"
            "  tmp_sign = arg_1\n"
            "  if (tmp_sign < 0.0) then\n"
            "    res_sign = res_sign * -1.0\n"
            "  end if\n"
            "  psyir_tmp = res_sign\n\n"
            "end subroutine sign_example\n".format(output)) in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
示例#6
0
def test_correct_2sign(tmpdir):
    '''Check that a valid example produces the expected output when there
    is more than one SIGN in an expression.

    '''
    Config.get().api = "nemo"
    operation = example_psyir(lambda arg: BinaryOperation.create(
        BinaryOperation.Operator.MUL, arg, Literal("3.14", REAL_TYPE)))
    assignment = operation.parent
    sign_op = BinaryOperation.create(BinaryOperation.Operator.SIGN,
                                     Literal("1.0", REAL_TYPE),
                                     Literal("1.0", REAL_TYPE))
    op1 = BinaryOperation.create(BinaryOperation.Operator.ADD, sign_op,
                                 operation)
    op1.parent = assignment
    assignment.children[1] = op1
    writer = FortranWriter()
    result = writer(operation.root)
    assert ("subroutine sign_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n\n"
            "  psyir_tmp=SIGN(1.0, 1.0) + SIGN(arg * 3.14, arg_1)\n\n"
            "end subroutine sign_example\n") in result
    trans = Sign2CodeTrans()
    trans.apply(operation, operation.root.symbol_table)
    trans.apply(sign_op, operation.root.symbol_table)
    result = writer(operation.root)
    assert ("subroutine sign_example(arg,arg_1)\n"
            "  real, intent(inout) :: arg\n"
            "  real, intent(inout) :: arg_1\n"
            "  real :: psyir_tmp\n"
            "  real :: res_sign\n"
            "  real :: tmp_sign\n"
            "  real :: res_abs\n"
            "  real :: tmp_abs\n"
            "  real :: res_sign_1\n"
            "  real :: tmp_sign_1\n"
            "  real :: res_abs_1\n"
            "  real :: tmp_abs_1\n\n"
            "  tmp_abs=arg * 3.14\n"
            "  if (tmp_abs > 0.0) then\n"
            "    res_abs=tmp_abs\n"
            "  else\n"
            "    res_abs=tmp_abs * -1.0\n"
            "  end if\n"
            "  res_sign=res_abs\n"
            "  tmp_sign=arg_1\n"
            "  if (tmp_sign < 0.0) then\n"
            "    res_sign=res_sign * -1.0\n"
            "  end if\n"
            "  tmp_abs_1=1.0\n"
            "  if (tmp_abs_1 > 0.0) then\n"
            "    res_abs_1=tmp_abs_1\n"
            "  else\n"
            "    res_abs_1=tmp_abs_1 * -1.0\n"
            "  end if\n"
            "  res_sign_1=res_abs_1\n"
            "  tmp_sign_1=1.0\n"
            "  if (tmp_sign_1 < 0.0) then\n"
            "    res_sign_1=res_sign_1 * -1.0\n"
            "  end if\n"
            "  psyir_tmp=res_sign_1 + res_sign\n\n"
            "end subroutine sign_example\n") in result
    assert Compile(tmpdir).string_compiles(result)
    # Remove the created config instance
    Config._instance = None
示例#7
0
def make_sir_compliant(schedule):
    '''
    Applies various transformations to the supplied schedule to replace any
    features that cannot be represented in SIR with alternative forms:

    1. Converts any accesses of individual array elements into 1-trip loops.
    2. Transforms array assignments into loops.
    3. Replaces any ABS, SIGN, MIN or MAX intrinsics with equivalent PSyIR.
    4. Hoists any loop-invariant assignments out of loops over levels.

    :param schedule: the schedule to transform.
    :type schedule: :py:class:`psyclone.psyir.nodes.Schedule`

    '''
    abs_trans = Abs2CodeTrans()
    sign_trans = Sign2CodeTrans()
    min_trans = Min2CodeTrans()
    max_trans = Max2CodeTrans()
    array_range_trans = NemoAllArrayRange2LoopTrans()
    array_access_trans = NemoAllArrayAccess2LoopTrans()
    hoist_trans = HoistTrans()

    # Transform any single index accesses in array assignments
    # (e.g. a(1)) into 1-trip loops.
    for assignment in schedule.walk(Assignment):
        array_access_trans.apply(assignment)

    # Transform any array assignments (Fortran ':' notation) into loops.
    for assignment in schedule.walk(Assignment):
        array_range_trans.apply(assignment)

    for kernel in schedule.walk(NemoKern):

        kernel_schedule = kernel.get_kernel_schedule()
        for oper in kernel_schedule.walk(Operation):
            if oper.operator == UnaryOperation.Operator.ABS:
                # Apply ABS transformation
                abs_trans.apply(oper)
            elif oper.operator == BinaryOperation.Operator.SIGN:
                # Apply SIGN transformation
                sign_trans.apply(oper)
            elif oper.operator in [BinaryOperation.Operator.MIN,
                                   NaryOperation.Operator.MIN]:
                # Apply (2-n arg) MIN transformation
                min_trans.apply(oper)
            elif oper.operator in [BinaryOperation.Operator.MAX,
                                   NaryOperation.Operator.MAX]:
                # Apply (2-n arg) MAX transformation
                max_trans.apply(oper)

    # Remove any loop invariant assignments inside k-loops to make
    # them perfectly nested. At the moment this transformation
    # does not perform any dependence analysis validation so could
    # move code that should not be moved, see issue
    # #1387. However, it is known that it is safe do apply this
    # transformation to this particular code
    # (tra_adv_compute.F90).
    for loop in schedule.loops():
        # outermost only
        if loop.loop_type == "levels":
            for child in loop.loop_body[:]:
                if isinstance(child, Assignment):
                    hoist_trans.apply(child)