def test_cw_gen_local_variable(monkeypatch): '''Check the CWriter class gen_local_variable method produces the expected declarations. ''' cwriter = CWriter() monkeypatch.setattr(cwriter, "gen_declaration", lambda x: "<declaration>") # Local variables are declared as single statements symbol = DataSymbol("dummy1", INTEGER_TYPE) result = cwriter.gen_local_variable(symbol) # Result should include the mocked gen_declaration and ';\n' assert result == "<declaration>;\n"
def test_gocean_acc_parallel(): '''Test that an ACC PARALLEL directive in a 'classical' API (gocean here) is created correctly. ''' _, invoke = get_invoke("single_invoke.f90", "gocean1.0", idx=0, dist_mem=False) ptrans = ACCParallelTrans() ptrans.apply(invoke.schedule[0]) # Now remove the GOKern (since it's not yet supported in the # visitor pattern) and replace it with a simple assignment # TODO: #440 tracks this replace_child_with_assignment(invoke.schedule[0].dir_body) # omp_sched is a GOInvokeSchedule, which is not yet supported. # So only convert starting from the OMPParallelDirective. Also, disable # node validation so as to avoid the need for a data region. fvisitor = FortranWriter(check_global_constraints=False) result = fvisitor(invoke.schedule[0]) correct = '''!$acc begin parallel default(present) a = b !$acc end parallel''' assert correct in result cvisitor = CWriter(check_global_constraints=False) with pytest.raises(VisitorError) as err: _ = cvisitor(invoke.schedule[0]) assert "Unsupported node 'ACCParallelDirective' found" in str(err.value)
def test_gocean_omp_parallel(): '''Test that an OMP PARALLEL directive in a 'classical' API (gocean here) is created correctly. ''' from psyclone.transformations import OMPParallelTrans _, invoke = get_invoke("single_invoke.f90", "gocean1.0", idx=0) omp = OMPParallelTrans() omp_sched, _ = omp.apply(invoke.schedule[0]) # Now remove the GOKern (since it's not yet supported in the # visitor pattern) and replace it with a simple assignment # TODO: #440 tracks this replace_child_with_assignment(omp_sched[0]) # omp_sched is a GOInvokeSchedule, which is not yet supported. # So only convert starting from the OMPParallelDirective fvisitor = FortranWriter() result = fvisitor(omp_sched[0]) correct = '''!$omp parallel a=b !$omp end parallel''' assert correct in result cvisitor = CWriter() # Remove newlines for easier RE matching result = cvisitor(omp_sched[0]) correct = '''#pragma omp parallel { a = b; }''' result = cvisitor(omp_sched[0]) assert correct in result
def test_nemo_acc_kernels(default_present, expected, parser): ''' Tests that an OpenACC kernels directive is handled correctly in the NEMO API. ''' # Generate fparser2 parse tree from Fortran code. reader = FortranStringReader(NEMO_TEST_CODE) code = parser(reader) psy = PSyFactory("nemo", distributed_memory=False).create(code) nemo_sched = psy.invokes.invoke_list[0].schedule # Now apply a kernels transform ktrans = ACCKernelsTrans() options = {"default_present": default_present} ktrans.apply(nemo_sched[0], options) fvisitor = FortranWriter() result = fvisitor(nemo_sched) correct = '''!$acc kernels{0} do i = 1, 20, 2 a = 2 * i + d(i) c(i) = a b(i) = b(i) + a + c(i) enddo !$acc end kernels'''.format(expected) assert correct in result cvisitor = CWriter() with pytest.raises(VisitorError) as err: _ = cvisitor(nemo_sched[0]) assert "Unsupported node 'ACCKernelsDirective' found" in str(err.value)
def test_nemo_acc_parallel(parser): '''Tests that an OpenACC parallel directive in NEMO is handled correctly. ''' # Generate fparser2 parse tree from Fortran code. reader = FortranStringReader(NEMO_TEST_CODE) code = parser(reader) psy = PSyFactory("nemo", distributed_memory=False).create(code) nemo_sched = psy.invokes.invoke_list[0].schedule # Now apply an ACC parallel transform dtrans = ACCDataTrans() ktrans = ACCParallelTrans() ktrans.apply(nemo_sched[0]) dtrans.apply(nemo_sched[0]) # Disable node validation to avoid having to add a data region fort_writer = FortranWriter(check_global_constraints=False) result = fort_writer(nemo_sched) correct = '''!$acc begin parallel default(present) do i = 1, 20, 2 a = 2 * i + d(i) c(i) = a b(i) = b(i) + a + c(i) enddo !$acc end parallel''' assert correct in result cvisitor = CWriter(check_global_constraints=False) with pytest.raises(VisitorError) as err: _ = cvisitor(nemo_sched[0]) assert "Unsupported node 'ACCDataDirective' found" in str(err.value)
def test_cw_array(): '''Check the CWriter class array method correctly prints out the C representation of an array. ''' cwriter = CWriter() symbol = DataSymbol('a', REAL_TYPE) arr = ArrayReference(symbol) lit = Literal('0.0', REAL_TYPE) assignment = Assignment.create(arr, 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.value) # Dimensions can be references, literals or operations arr.addchild(Reference(DataSymbol('b', INTEGER_TYPE), parent=arr)) arr.addchild(Literal('1', INTEGER_TYPE, parent=arr)) uop = UnaryOperation.create(UnaryOperation.Operator.MINUS, Literal('2', INTEGER_TYPE)) uop.parent = arr 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 test_cw_loop(): '''Tests writing out a Loop node in C. It parses Fortran code and outputs it as C. Note that this is atm a literal translation, the loops are not functionally identical to Fortran, see TODO #523. ''' from psyclone.tests.utilities import create_schedule # Generate PSyIR from Fortran code. code = ''' module test contains subroutine tmp() integer :: i, a integer, dimension(:) :: b do i = 1, 20, 2 a = 2 * i enddo end subroutine tmp end module test''' schedule = create_schedule(code, "tmp") cvisitor = CWriter() result = cvisitor(schedule[0]) correct = '''for(i=1; i<=20; i+=2) { a = (2 * i); }''' result = cvisitor(schedule[0]) assert correct in result
def test_cw_loop(fortran_reader): '''Tests writing out a Loop node in C. It parses Fortran code and outputs it as C. Note that this is atm a literal translation, the loops are not functionally identical to Fortran, see TODO #523. ''' # Generate PSyIR from Fortran code. code = ''' module test contains subroutine tmp() integer :: i, a integer, dimension(:) :: b do i = 1, 20, 2 a = 2 * i enddo end subroutine tmp end module test''' container = fortran_reader.psyir_from_source(code).children[0] module = container.children[0] cvisitor = CWriter() result = cvisitor(module[0]) correct = '''for(i=1; i<=20; i+=2) { a = (2 * i); }''' result = cvisitor(module[0]) assert correct in result
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 test_cw_assignment(): '''Check the CWriter class assignment method generate the appropriate output. ''' assignment = Assignment.create(Reference(DataSymbol('a', REAL_TYPE)), Reference(DataSymbol('b', REAL_TYPE))) # Generate C from the PSyIR schedule cwriter = CWriter() result = cwriter(assignment) assert result == "a = b;\n"
def test_cw_codeblock(): '''Check the CWriter class codeblock method raises the expected error. ''' cblock = CodeBlock([], "dummy") cwriter = CWriter() with pytest.raises(VisitorError) as error: _ = cwriter(cblock) assert "CodeBlocks can not be translated to C." in str(error.value)
def test_cw_binaryoperator(): '''Check the CWriter class binary_operation method correctly prints out the C representation of any given BinaryOperation. ''' cwriter = CWriter() # Test UnaryOperation without children. binary_operation = BinaryOperation(BinaryOperation.Operator.ADD) with pytest.raises(VisitorError) as err: _ = cwriter(binary_operation) assert ("BinaryOperation malformed or incomplete. It should have " "exactly 2 children, but found 0." in str(err.value)) # Test with children ref1 = Reference(DataSymbol("a", REAL_TYPE)) ref2 = Reference(DataSymbol("b", REAL_TYPE)) binary_operation = BinaryOperation.create(BinaryOperation.Operator.ADD, ref1, ref2) assert cwriter(binary_operation) == '(a + b)' # Test all supported Operators test_list = ((BinaryOperation.Operator.ADD, '(a + b)'), (BinaryOperation.Operator.SUB, '(a - b)'), (BinaryOperation.Operator.MUL, '(a * b)'), (BinaryOperation.Operator.DIV, '(a / b)'), (BinaryOperation.Operator.REM, '(a % b)'), (BinaryOperation.Operator.POW, 'pow(a, b)'), (BinaryOperation.Operator.EQ, '(a == b)'), (BinaryOperation.Operator.NE, '(a != b)'), (BinaryOperation.Operator.GT, '(a > b)'), (BinaryOperation.Operator.GE, '(a >= b)'), (BinaryOperation.Operator.LT, '(a < b)'), (BinaryOperation.Operator.LE, '(a <= b)'), (BinaryOperation.Operator.AND, '(a && b)'), (BinaryOperation.Operator.OR, '(a || b)'), (BinaryOperation.Operator.SIGN, 'copysign(a, b)')) for operator, expected in test_list: binary_operation._operator = operator assert cwriter(binary_operation) == expected # Test that an unsupported operator raises a error class Unsupported(object): '''Dummy class''' def __init__(self): pass binary_operation._operator = Unsupported with pytest.raises(VisitorError) as err: _ = cwriter(binary_operation) assert "The C backend does not support the '" in str(err.value) assert "' operator." in str(err.value)
def test_cw_binaryoperator(): '''Check the CWriter class binary_operation method correctly prints out the C representation of any given BinaryOperation. ''' cwriter = CWriter() # Test UnaryOperation without children. binary_operation = BinaryOperation(BinaryOperation.Operator.ADD) with pytest.raises(VisitorError) as err: _ = cwriter(binary_operation) assert("BinaryOperation malformed or incomplete. It should have " "exactly 2 children, but found 0." in str(err.value)) # Add children ref1 = Reference("a", binary_operation) ref2 = Reference("b", binary_operation) binary_operation.addchild(ref1) binary_operation.addchild(ref2) assert cwriter(binary_operation) == '(a + b)' # Test all supported Operators test_list = ((BinaryOperation.Operator.ADD, '(a + b)'), (BinaryOperation.Operator.SUB, '(a - b)'), (BinaryOperation.Operator.MUL, '(a * b)'), (BinaryOperation.Operator.DIV, '(a / b)'), (BinaryOperation.Operator.REM, '(a % b)'), (BinaryOperation.Operator.POW, 'pow(a, b)'), (BinaryOperation.Operator.EQ, '(a == b)'), (BinaryOperation.Operator.NE, '(a != b)'), (BinaryOperation.Operator.GT, '(a > b)'), (BinaryOperation.Operator.GE, '(a >= b)'), (BinaryOperation.Operator.LT, '(a < b)'), (BinaryOperation.Operator.LE, '(a <= b)'), (BinaryOperation.Operator.AND, '(a && b)'), (BinaryOperation.Operator.OR, '(a || b)'), (BinaryOperation.Operator.SIGN, 'copysign(a, b)')) for operator, expected in test_list: binary_operation._operator = operator assert cwriter(binary_operation) == 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 binary_operation._operator = Unsupported with pytest.raises(VisitorError) as err: _ = cwriter(binary_operation) assert "The C backend does not support the '" in str(err) assert "' operator." in str(err)
def test_nemo_omp_do(fortran_reader): '''Tests if an OpenMP do directive in NEMO is handled correctly. ''' # Generate fparser2 parse tree from Fortran code. code = ''' module test contains subroutine tmp() integer :: i, a integer, dimension(:) :: b do i = 1, 20, 2 a = 2 * i b(i) = b(i) + a enddo end subroutine tmp end module test''' psyir = fortran_reader.psyir_from_source(code) schedule = psyir.children[0].children[0] # Now apply a parallel transform omp_loop = OMPLoopTrans() omp_loop.apply(schedule[0]) # By default the visitor should raise an exception because the loop # directive is not inside a parallel region fvisitor_with_checks = FortranWriter() with pytest.raises(GenerationError) as err: fvisitor_with_checks(schedule) assert ("OMPDoDirective must be inside an OMP parallel region but could " "not find an ancestor OMPParallelDirective" in str(err.value)) # Disable checks on global constraints to remove need for parallel region fvisitor = FortranWriter(check_global_constraints=False) result = fvisitor(schedule) correct = ''' !$omp do schedule(static) do i = 1, 20, 2 a = 2 * i b(i) = b(i) + a enddo !$omp end do''' assert correct in result cvisitor = CWriter(check_global_constraints=False) result = cvisitor(schedule[0]) correct = '''#pragma omp do schedule(static) { for(i=1; i<=20; i+=2) { a = (2 * i); b[i] = (b[i] + a); } }''' assert correct in result
def test_cw_size(): ''' Check the CWriter class SIZE method raises the expected error since there is no C equivalent. ''' cwriter = CWriter() arr = ArrayReference(DataSymbol('a', INTEGER_TYPE)) lit = Literal('1', INTEGER_TYPE) size = BinaryOperation.create(BinaryOperation.Operator.SIZE, arr, lit) lhs = Reference(DataSymbol('length', INTEGER_TYPE)) assignment = Assignment.create(lhs, size) with pytest.raises(VisitorError) as excinfo: cwriter(assignment) assert ("C backend does not support the 'Operator.SIZE' operator" in str(excinfo.value))
def test_cw_literal(): '''Check the CWriter class literal method correctly prints out the C representation of a Literal. ''' cwriter = CWriter() lit = Literal('1', INTEGER_TYPE) assert cwriter(lit) == '1' # Test that scientific notation is output correctly lit = Literal("3e5", REAL_TYPE, None) assert cwriter(lit) == '3e5'
def test_nemo_omp_parallel(): '''Tests if an OpenMP parallel directive in NEMO is handled correctly. ''' # Generate fparser2 parse tree from Fortran code. code = ''' module test contains subroutine tmp() integer :: i, a integer, dimension(:) :: b do i = 1, 20, 2 a = 2 * i b(i) = b(i) + a enddo end subroutine tmp end module test''' schedule = create_schedule(code, "tmp") from psyclone.transformations import OMPParallelTrans # Now apply a parallel transform omp_par = OMPParallelTrans() # Note that the loop is not handled as nemo kernel, so the # omp node-type-check will find the assignment statement and # prevent application of omp parallel to the loop. So # disable the node type check so that omp parallel is applied. omp_par.apply(schedule[0], {"node-type-check": False}) fvisitor = FortranWriter() result = fvisitor(schedule) correct = '''!$omp parallel private(a,i) do i = 1, 20, 2 a=2 * i b(i)=b(i) + a enddo !$omp end parallel''' assert correct in result cvisitor = CWriter() result = cvisitor(schedule[0]) correct = '''#pragma omp parallel private(a,i) { for(i=1; i<=20; i+=2) { a = (2 * i); b[i] = (b[i] + a); } }''' result = cvisitor(schedule[0]) assert correct in result
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", CHARACTER_TYPE, 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 an error class Unsupported(object): # pylint: disable=missing-docstring pass unary_operation._operator = Unsupported with pytest.raises(NotImplementedError) as err: _ = cwriter(unary_operation) assert "The C backend does not support the '" in str(err.value) assert "' operator." in str(err.value)
def test_cw_ifblock(): '''Check the CWriter class ifblock method correctly prints out the C representation. ''' from psyclone.psyGen import IfBlock # Try with just a 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('a', 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)) ifblock2 = IfBlock(parent=ifblock.else_body) ifblock2.addchild(Reference('b', parent=ifblock2)) ifblock2.addchild(Schedule(parent=ifblock2)) ifblock2.if_body.addchild(Return(parent=ifblock2.if_body)) ifblock2.addchild(Schedule(parent=ifblock2)) ifblock2.else_body.addchild(Return(parent=ifblock2.else_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_cw_gen_declaration(): '''Check the CWriter class gen_declaration method produces the expected declarations. ''' cwriter = CWriter() # Basic entries symbol = DataSymbol("dummy1", INTEGER_TYPE) result = cwriter.gen_declaration(symbol) assert result == "int dummy1" symbol = DataSymbol("dummy1", CHARACTER_TYPE) result = cwriter.gen_declaration(symbol) assert result == "char dummy1" symbol = DataSymbol("dummy1", BOOLEAN_TYPE) result = cwriter.gen_declaration(symbol) assert result == "bool dummy1" # Array argument array_type = ArrayType(REAL_TYPE, [2, ArrayType.Extent.ATTRIBUTE, 2]) symbol = DataSymbol("dummy2", array_type, interface=ArgumentInterface( ArgumentInterface.Access.READ)) result = cwriter.gen_declaration(symbol) assert result == "double * restrict dummy2" # Array with unknown access array_type = ArrayType(INTEGER_TYPE, [2, ArrayType.Extent.ATTRIBUTE, 2]) symbol = DataSymbol("dummy2", array_type, interface=ArgumentInterface( ArgumentInterface.Access.UNKNOWN)) result = cwriter.gen_declaration(symbol) assert result == "int * restrict dummy2" # Check invalid datatype produces and error symbol._datatype = "invalid" with pytest.raises(NotImplementedError) as error: _ = cwriter.gen_declaration(symbol) assert "Could not generate the C definition for the variable 'dummy2', " \ "type 'invalid' is currently not supported." in str(error.value)
def test_cw_exception(): '''Check the CWriter class instance raises an exception if an unsupported PSyIR node is found. ''' # pylint: disable=abstract-method # Define a Node which will be unsupported by the visitor class Unsupported(Node): '''A PSyIR node that will not be supported by the C visitor.''' # pylint: enable=abstract-method unsupported = Unsupported() cwriter = CWriter() with pytest.raises(VisitorError) as excinfo: _ = cwriter(unsupported) assert "Unsupported node 'Unsupported' found" in str(excinfo.value)
def test_nemo_omp_parallel(): '''Tests if an OpenMP parallel directive in NEMO is handled correctly. ''' # Generate fparser2 parse tree from Fortran code. code = ''' module test contains subroutine tmp() integer :: i, a integer, dimension(:) :: b do i = 1, 20, 2 a = 2 * i b(i) = b(i) + a enddo end subroutine tmp end module test''' schedule = create_schedule(code, "tmp") from psyclone.transformations import OMPParallelTrans # Now apply a parallel transform omp_par = OMPParallelTrans() omp_par.apply(schedule[0]) fvisitor = FortranWriter() result = fvisitor(schedule) correct = '''!$omp parallel private(a,i) do i = 1, 20, 2 a=2 * i b(i)=b(i) + a enddo !$omp end parallel''' assert correct in result cvisitor = CWriter() result = cvisitor(schedule[0]) correct = '''#pragma omp parallel private(a,i) { for(i=1; i<=20; i+=2) { a = (2 * i); b[i] = (b[i] + a); } }''' result = cvisitor(schedule[0]) assert correct in result
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_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_cw_gen_declaration(): '''Check the CWriter class gen_declaration method produces the expected declarations. ''' cwriter = CWriter() # Basic entries symbol = Symbol("dummy1", "integer") result = cwriter.gen_declaration(symbol) assert result == "int dummy1" symbol = Symbol("dummy1", "character") result = cwriter.gen_declaration(symbol) assert result == "char dummy1" symbol = Symbol("dummy1", "boolean") result = cwriter.gen_declaration(symbol) assert result == "bool dummy1" # Array argument symbol = Symbol("dummy2", "real", shape=[2, None, 2], interface=Symbol.Argument(access=Symbol.Access.READ)) result = cwriter.gen_declaration(symbol) assert result == "double * restrict dummy2" # Array with unknown intent symbol = Symbol("dummy2", "integer", shape=[2, None, 2], interface=Symbol.Argument(access=Symbol.Access.UNKNOWN)) result = cwriter.gen_declaration(symbol) assert result == "int * restrict dummy2" # Check invalid datatype produces and error symbol._datatype = "invalid" with pytest.raises(NotImplementedError) as error: _ = cwriter.gen_declaration(symbol) assert "Could not generate the C definition for the variable 'dummy2', " \ "type 'invalid' is currently not supported." in str(error)
def test_gocean_omp_do(): '''Test that an OMP DO directive in a 'classical' API (gocean here) is created correctly. ''' from psyclone.transformations import OMPLoopTrans _, invoke = get_invoke("single_invoke.f90", "gocean1.0", idx=0, dist_mem=False) omp = OMPLoopTrans() omp_sched, _ = omp.apply(invoke.schedule[0]) # Now remove the GOKern (since it's not yet supported in the # visitor pattern) and replace it with a simple assignment. # While this is invalid usage of OMP (omp must have a loop, # not an assignment inside), it is necessary because GOLoops # are not supported yet, and it is sufficient to test that the # visitor pattern creates correct OMP DO directives. # TODO #440 fixes this. replace_child_with_assignment(omp_sched[0].dir_body) fvisitor = FortranWriter() # GOInvokeSchedule is not yet supported, so start with # the OMP node: result = fvisitor(omp_sched[0]) correct = '''!$omp do schedule(static) a = b !$omp end do''' assert correct in result cvisitor = CWriter() # Remove newlines for easier RE matching result = cvisitor(omp_sched[0]) correct = '''#pragma omp do schedule(static) { a = b; }''' assert correct in result
def test_gocean_omp_do(): '''Test that an OMP DO directive in a 'classical' API (gocean here) is created correctly. ''' _, invoke = get_invoke("single_invoke.f90", "gocean1.0", idx=0, dist_mem=False) omp = OMPLoopTrans() _, _ = omp.apply(invoke.schedule[0]) # Now remove the GOKern (since it's not yet supported in the # visitor pattern) and replace it with a simple assignment. # While this is invalid usage of OMP (omp must have a loop, # not an assignment inside), it is necessary because GOLoops # are not supported yet, and it is sufficient to test that the # visitor pattern creates correct OMP DO directives. # TODO #440 fixes this. replace_child_with_assignment(invoke.schedule[0].dir_body) # Disable validation checks to avoid having to add a parallel region fvisitor = FortranWriter(check_global_constraints=False) # GOInvokeSchedule is not yet supported, so start with # the OMP node: result = fvisitor(invoke.schedule[0]) correct = '''!$omp do schedule(static) a = b !$omp end do''' assert correct in result cvisitor = CWriter(check_global_constraints=False) result = cvisitor(invoke.schedule[0]) correct = '''#pragma omp do schedule(static) { a = b; }''' assert correct in result
def test_cw_assignment_and_reference(): '''Check the CWriter class assignment and reference methods generate the appropriate output. Also check that a reference visit raises an exception if it has children as this is not expected. ''' assignment = Assignment() assignment.addchild(Reference('a', parent=assignment)) assignment.addchild(Reference('b', parent=assignment)) # Generate C from the PSyIR schedule cwriter = CWriter() result = cwriter(assignment) assert result == "a = b;\n" # Now add a child to the reference node assignment.lhs.addchild(Node(parent=assignment)) # Generate C from the PSyIR schedule with pytest.raises(VisitorError) as excinfo: result = cwriter(assignment) assert "Expecting a Reference with no children but found: " \ in str(excinfo)
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 if __name__ == "__main__": psyir_tree = create_psyir_tree() # Write out the code as Fortran writer = FortranWriter() result = writer(psyir_tree) print(result) # Write out the code as C. At the moment NaryOperator, KernelSchedule # and Container are not supported in the C backend so the full example # can't be output. writer = CWriter() result = writer(psyir_tree.children[0].children[3]) print(result)
# 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") 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) # Write out the code as Fortran WRITER = FortranWriter() RESULT = WRITER(CONTAINER) print(RESULT) # Write out the code as C. At the moment NaryOperator, KernelSchedule # and Container are not supported in the C backend so the full example # can't be output. WRITER = CWriter() RESULT = WRITER(LOOP) print(RESULT)