def test_basegen_start_parent_loop_omp_end_dbg(capsys): '''Check the debug option to the start_parent_loop method when we have an OpenMP end directive''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) dgen = DirectiveGen(sub, "omp", "end", "do", "") sub.add(dgen) loop = DoGen(sub, "it", "1", "10") sub.add(loop) call = CallGen(loop, "testcall") loop.add(call) call.start_parent_loop(debug=True) out, _ = capsys.readouterr() print out expected = ("Parent is a do loop so moving to the parent\n" "The type of the current node is now <class " "'fparser.one.block_statements.Do'>\n" "The type of parent is <class " "'fparser.one.block_statements.Subroutine'>\n" "Finding the loops position in its parent ...\n" "The loop's index is 1\n" "The type of the object at the index is <class " "'fparser.one.block_statements.Do'>\n" "If preceding node is a directive then move back one\n" "preceding node is a directive so find out what type ...\n") assert expected in out
def test_imp_none_exception_if_wrong_parent(): ''' test that an exception is thrown if implicit none is added and the parent is not a module or a subroutine ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) dogen = DoGen(sub, "i", "1", "10") sub.add(dogen) with pytest.raises(Exception): dogen.add(ImplicitNoneGen(dogen))
def gen_code(self, parent): ''' Generate the Fortran Loop and any associated code. :param parent: the node in the f2pygen AST to which to add content. :type parent: :py:class:`psyclone.f2pygen.SubroutineGen` ''' # Avoid circular dependency # pylint: disable=import-outside-toplevel from psyclone.psyGen import zero_reduction_variables, InvokeSchedule def is_unit_literal(expr): ''' Check if the given expression is equal to the literal '1'. :param expr: a PSyIR expression. :type expr: :py:class:`psyclone.psyir.nodes.Node` :returns: True if it is equal to the literal '1', false otherwise. ''' return isinstance(expr, Literal) and expr.value == '1' if not self.is_openmp_parallel(): calls = self.reductions() zero_reduction_variables(calls, parent) invoke = self.ancestor(InvokeSchedule) if invoke.opencl or (is_unit_literal(self.start_expr) and is_unit_literal(self.stop_expr)): # no need for a loop for child in self.loop_body: child.gen_code(parent) else: # Avoid circular dependency # pylint: disable=import-outside-toplevel from psyclone.psyir.backend.fortran import FortranWriter # start/stop/step_expr are generated with the FortranWriter # backend, the rest of the loop with f2pygen. fwriter = FortranWriter() if is_unit_literal(self.step_expr): step_str = None else: step_str = fwriter(self.step_expr) do_stmt = DoGen(parent, self.variable.name, fwriter(self.start_expr), fwriter(self.stop_expr), step_str) # need to add do loop before children as children may want to add # info outside of do loop parent.add(do_stmt) for child in self.loop_body: child.gen_code(do_stmt) my_decl = DeclGen(parent, datatype="integer", entity_decls=[self.variable.name]) parent.add(my_decl)
def test_do_loop_with_increment(): ''' Test that we correctly generate code for a do loop with non-unit increment ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsub") module.add(sub) dogen = DoGen(sub, "it", "1", "10", step="2") sub.add(dogen) count = count_lines(sub.root, "DO it=1,10,2") assert count == 1
def test_basegen_start_parent_loop_dbg(capsys): '''Check the debug option to the start_parent_loop method''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) loop = DoGen(sub, "it", "1", "10") sub.add(loop) call = CallGen(loop, "testcall") loop.add(call) call.start_parent_loop(debug=True) out, _ = capsys.readouterr() print out expected = ("Parent is a do loop so moving to the parent\n" "The type of the current node is now <class " "'fparser.one.block_statements.Do'>\n" "The type of parent is <class " "'fparser.one.block_statements.Subroutine'>\n" "Finding the loops position in its parent ...\n" "The loop's index is 0\n") assert expected in out
def test_add_before(): ''' add the new code before a particular object ''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine") module.add(subroutine) loop = DoGen(subroutine, "it", "1", "10") subroutine.add(loop) call = CallGen(subroutine, "testcall") subroutine.add(call, position=["before", loop.root]) lines = str(module.root).splitlines() # the call should be inserted before the loop print lines assert "SUBROUTINE testsubroutine" in lines[3] assert "CALL testcall" in lines[4] assert "DO it=1,10" in lines[5]
def test_do_loop_add_after(): ''' Test that we correctly generate code for a do loop when adding a child to it with position *after* ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsub") module.add(sub) dogen = DoGen(sub, "it", "1", "10", step="2") sub.add(dogen) assign1 = AssignGen(dogen, lhs="happy", rhs=".TRUE.") dogen.add(assign1) assign2 = AssignGen(dogen, lhs="sad", rhs=".FALSE.") dogen.add(assign2, position=["before", assign1.root]) a1_line = line_number(sub.root, "happy = ") a2_line = line_number(sub.root, "sad = ") assert a1_line > a2_line