Skip to content

Commit

Permalink
Merge pull request #2309 from stfc/1558_param_ordering
Browse files Browse the repository at this point in the history
(Closes #1558) support out-of-order parameter statements
  • Loading branch information
sergisiso authored Sep 14, 2023
2 parents f54db94 + 35ad0b9 commit f408b3b
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 43 deletions.
2 changes: 2 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
107 changes: 67 additions & 40 deletions src/psyclone/psyir/frontend/fparser2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
'''
Expand Down Expand Up @@ -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.
Expand Down
36 changes: 33 additions & 3 deletions src/psyclone/tests/psyir/frontend/fparser2_parameter_stmts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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

0 comments on commit f408b3b

Please sign in to comment.