From dcbc0cb4bb578b7778373fa79860236191057745 Mon Sep 17 00:00:00 2001 From: Andrew Porter Date: Tue, 12 Sep 2023 15:36:44 +0100 Subject: [PATCH 1/2] #1558 mv parameter processing into separate routine and add test --- src/psyclone/psyir/frontend/fparser2.py | 107 +++++++++++------- .../frontend/fparser2_parameter_stmts_test.py | 36 +++++- 2 files changed, 100 insertions(+), 43 deletions(-) diff --git a/src/psyclone/psyir/frontend/fparser2.py b/src/psyclone/psyir/frontend/fparser2.py index 6b3287ab63..191c3d3984 100644 --- a/src/psyclone/psyir/frontend/fparser2.py +++ b/src/psyclone/psyir/frontend/fparser2.py @@ -2248,6 +2248,63 @@ def _get_partial_datatype(self, node, scope, visibility_map): return datatype, init_expr + def _process_parameter_stmts(self, nodes, parent): + ''' + Examine the supplied list of fparser2 nodes and handle any + PARAMETER statements. This is done separately so that it can be + performed after all the declarations have been processed (since + a PARAMETER statement can come *before* a symbol's declaration.) + + :param nodes: fparser2 AST nodes containing declaration statements. + :type nodes: list of :py:class:`fparser.two.utils.Base` + :param parent: PSyIR node in which to insert the symbols found. + :type parent: :py:class:`psyclone.psyir.nodes.KernelSchedule` + + :raises NotImplementedError: if there are any issues parsing a + parameter statement. + + ''' + for node in nodes: + if not isinstance(node, Fortran2003.Implicit_Part): + continue + for stmt in node.children: + if not isinstance(stmt, Fortran2003.Parameter_Stmt): + continue + for parameter_def in stmt.children[1].items: + name, expr = parameter_def.items + try: + symbol = parent.symbol_table.lookup(str(name)) + except Exception as err: + # If there is any problem put the whole thing + # in a codeblock (as we presume the original + # code is correct). + raise NotImplementedError( + f"Could not parse '{stmt}' because: " + f"{err}.") from err + + if not isinstance(symbol, DataSymbol): + raise NotImplementedError( + f"Could not parse '{stmt}' because " + f"'{symbol.name}' is not a DataSymbol.") + if isinstance(symbol.datatype, UnknownType): + raise NotImplementedError( + f"Could not parse '{stmt}' because " + f"'{symbol.name}' has an UnknownType.") + + # Parse its initialization into a dummy Assignment + # (but connected to the parent scope since symbols + # must be resolved) + dummynode = Assignment(parent=parent) + self.process_nodes(parent=dummynode, nodes=[expr]) + + # Add the initialization expression in the symbol + # constant_value attribute + ct_expr = dummynode.children[0].detach() + symbol.initial_value = ct_expr + symbol.is_constant = True + # Ensure the interface to this Symbol is static + symbol.interface = StaticInterface() + def process_declarations(self, parent, nodes, arg_list, visibility_map=None): ''' @@ -2433,51 +2490,21 @@ def process_declarations(self, parent, nodes, arg_list, # These node types are handled separately pass elif isinstance(node, Fortran2003.Implicit_Part): - for stmt in node.children: - if isinstance(stmt, Fortran2003.Parameter_Stmt): - for parameter_def in stmt.children[1].items: - name, expr = parameter_def.items - try: - symbol = parent.symbol_table.lookup(str(name)) - except Exception as err: - # If there is any problem put the whole thing - # in a codeblock (as we presume the original - # code is correct). - raise NotImplementedError( - f"Could not parse '{stmt}' because: " - f"{err}.") from err - - if not isinstance(symbol, DataSymbol): - raise NotImplementedError( - f"Could not parse '{stmt}' because " - f"'{symbol.name}' is not a DataSymbol.") - if isinstance(symbol.datatype, UnknownType): - raise NotImplementedError( - f"Could not parse '{stmt}' because " - f"'{symbol.name}' has an UnknownType.") - - # Parse its initialization into a dummy Assignment - # (but connected to the parent scope since symbols - # must be resolved) - dummynode = Assignment(parent=parent) - self.process_nodes(parent=dummynode, nodes=[expr]) - - # Add the initialization expression in the symbol - # constant_value attribute - ct_expr = dummynode.children[0].detach() - symbol.initial_value = ct_expr - symbol.is_constant = True - # Ensure the interface to this Symbol is static - symbol.interface = StaticInterface() - else: - # TODO #1254: We currently silently ignore the rest of - # the Implicit_Part statements - pass + # Any PARAMETER statements are handled separately by the + # call to _process_parameter_stmts below. + # TODO #1254: We currently silently ignore the rest of + # the Implicit_Part statements + pass else: raise NotImplementedError( f"Error processing declarations: fparser2 node of type " f"'{type(node).__name__}' not supported") + # Process the nodes again, looking for PARAMETER statements. This is + # done after the main declarations loop because they modify existing + # symbols and can appear in any order. + self._process_parameter_stmts(nodes, parent) + # We process the nodes again looking for common blocks. We do this # here, after the main declarations loop, because they modify the # interface of existing symbols and can appear in any order. diff --git a/src/psyclone/tests/psyir/frontend/fparser2_parameter_stmts_test.py b/src/psyclone/tests/psyir/frontend/fparser2_parameter_stmts_test.py index a1cd5f7a2f..4685639b04 100644 --- a/src/psyclone/tests/psyir/frontend/fparser2_parameter_stmts_test.py +++ b/src/psyclone/tests/psyir/frontend/fparser2_parameter_stmts_test.py @@ -41,9 +41,10 @@ from fparser.common.readfortran import FortranStringReader from fparser.two.Fortran2003 import Specification_Part from psyclone.psyir.frontend.fparser2 import Fparser2Reader -from psyclone.psyir.nodes import Routine, Literal, BinaryOperation, \ - Container, CodeBlock, Reference -from psyclone.psyir.symbols import Symbol, StaticInterface +from psyclone.psyir.nodes import ( + Routine, Literal, BinaryOperation, Container, CodeBlock, Reference, + UnaryOperation) +from psyclone.psyir.symbols import Symbol, StaticInterface, ScalarType @pytest.mark.usefixtures("f2008_parser") @@ -230,3 +231,32 @@ def test_unsupported_parameter_statements_produce_codeblocks(fortran_reader, END SUBROUTINE my_sub END MODULE my_mod ''' + + +def test_parameter_before_decln(fortran_reader): + ''' + Test when a PARAMETER statement occurs *before* the named symbol is + actually declared. + ''' + psyir = fortran_reader.psyir_from_source('''\ +module test_mod + implicit none + PARAMETER(MPI_DISPLACEMENT_CURRENT = - 54278278) + INTEGER*8 :: MPI_DISPLACEMENT_CURRENT + PARAMETER(MPI_TROUBLE = atan(-1.0)) + real :: mpi_trouble +contains + + subroutine some_sub() + end subroutine some_sub +end module test_mod +''') + # We should have succeeded in parsing the code and creating a Container. + assert isinstance(psyir.children[0], Container) + sym = psyir.children[0].symbol_table.lookup("MPI_DISPLACEMENT_CURRENT") + # The Symbol should be a runtime constant with an initial value. + assert sym.is_constant + assert isinstance(sym.initial_value, UnaryOperation) + sym2 = psyir.children[0].symbol_table.lookup("MPI_TROUBLE") + assert sym2.is_constant + assert sym2.datatype.intrinsic == ScalarType.Intrinsic.REAL From 35ad0b9e763f0b5fb975339bb073f71392f26556 Mon Sep 17 00:00:00 2001 From: Sergi Siso Date: Thu, 14 Sep 2023 11:44:56 +0100 Subject: [PATCH 2/2] #2309 Update changelog --- changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog b/changelog index f52c414c2e..61d166cab1 100644 --- a/changelog +++ b/changelog @@ -592,6 +592,8 @@ 199) PR #2293 for #2301. Add 'is_independent' property/query to Loop. + 200) PR #2309 for #1558. Add support for out-of-order parameter statements. + release 2.3.1 17th of June 2022 1) PR #1747 for #1720. Adds support for If blocks to PSyAD.