Skip to content

Commit

Permalink
#2422 add replace() method to GenericSymbolInterface and use in psyad…
Browse files Browse the repository at this point in the history
… routine renaming
  • Loading branch information
arporter committed Jan 22, 2024
1 parent fae0056 commit 8bced83
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 11 deletions.
11 changes: 5 additions & 6 deletions src/psyclone/psyad/domain/lfric/lfric_adjoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ def generate_lfric_adjoint(tl_psyir, active_variables):
interfaced_routines = dict()
for gisym in ctr_table.symbols:
if isinstance(gisym, GenericInterfaceSymbol):
for rsym in gisym.routines:
if rsym in interfaced_routines:
interfaced_routines[rsym].append(gisym)
for routine in gisym.routines:
if routine.symbol in interfaced_routines:
interfaced_routines[routine.symbol].append(gisym)

Check warning on line 131 in src/psyclone/psyad/domain/lfric/lfric_adjoint.py

View check run for this annotation

Codecov / codecov/patch

src/psyclone/psyad/domain/lfric/lfric_adjoint.py#L129-L131

Added lines #L129 - L131 were not covered by tests
else:
interfaced_routines[rsym] = [gisym]
interfaced_routines[routine.symbol] = [gisym]

Check warning on line 133 in src/psyclone/psyad/domain/lfric/lfric_adjoint.py

View check run for this annotation

Codecov / codecov/patch

src/psyclone/psyad/domain/lfric/lfric_adjoint.py#L133

Added line #L133 was not covered by tests

for routine in routines:

Expand All @@ -143,8 +143,7 @@ def generate_lfric_adjoint(tl_psyir, active_variables):
visibility=kernel_sym.visibility)
if kernel_sym in interfaced_routines:
for gsym in interfaced_routines[kernel_sym]:
gsym.routines.remove(kernel_sym)
gsym.routines.append(adj_kernel_sym)
gsym.replace(kernel_sym, adj_kernel_sym)

Check warning on line 146 in src/psyclone/psyad/domain/lfric/lfric_adjoint.py

View check run for this annotation

Codecov / codecov/patch

src/psyclone/psyad/domain/lfric/lfric_adjoint.py#L145-L146

Added lines #L145 - L146 were not covered by tests
ad_container.symbol_table.remove(kernel_sym)

routine.name = adj_kernel_sym.name
Expand Down
4 changes: 3 additions & 1 deletion src/psyclone/psyir/backend/fortran.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ def gen_interfacedecl(self, symbol, include_visibility=False):
decln = f"{self._nindent}interface {symbol.name}\n"
self._depth += 1
# Any module procedures.
routines = ", ".join([rsym.name for rsym in symbol.module_routines])
routines = ", ".join([rsym.name for rsym in symbol.container_routines])
if routines:
decln += f"{self._nindent}module procedure :: {routines}\n"
# Any other (external) procedures.
Expand All @@ -651,6 +651,8 @@ def gen_interfacedecl(self, symbol, include_visibility=False):
decln += f"{self._nindent}end interface {symbol.name}\n"

if include_visibility:
# Visibility of an interface has to be supplied as a separate
# statement.
if symbol.visibility == Symbol.Visibility.PRIVATE:
decln += f"{self._nindent}private {symbol.name}\n"
elif symbol.visibility == Symbol.Visibility.PUBLIC:
Expand Down
29 changes: 26 additions & 3 deletions src/psyclone/psyir/symbols/generic_interface_symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ def __init__(self, name, routines, **kwargs):
@property
def routines(self):
'''
:returns: all of the routines to which this interface provides access.
:returns: information on all of the routines to which this interface
provides access.
:rtype: list[tuple[:py:class:`psyclone.psyir.symbols.RoutineSymbol`,
bool]]
'''
Expand Down Expand Up @@ -107,9 +108,9 @@ def routines(self, values):
self._routines.append(self.RoutineInfo(item[0], item[1]))

@property
def module_routines(self):
def container_routines(self):
'''
:returns: those routines that are module procedures.
:returns: those routines that are defined in a Container.
:rtype: list[:py:class:`psyclone.psyir.symbols.RoutineSymbol`]
'''
result = []
Expand All @@ -130,6 +131,28 @@ def external_routines(self):
result.append(value.symbol)
return result

def replace(self, existing_sym, new_sym):
'''
Replace the specified RoutineSymbol with the new RoutineSymbol.
The 'from_container' property of the entry is preserved.
:param existing_sym: the RoutineSymbol to replace.
:type existing_sym: :py:class:`psyclone.psyir.symbols.RoutineSymbol`
:param new_sym: the new RoutineSymbol.
:type new_sym: :py:class:`psyclone.psyir.symbols.RoutineSymbol`
:raises ValueError: if the supplied RoutineSymbol is not referenced
by this interface.
'''
for idx, value in enumerate(self._routines):
if value.symbol is existing_sym:
self._routines[idx] = self.RoutineInfo(new_sym,
value.from_container)
return
raise ValueError(f"RoutineSymbol '{existing_sym.name}' not found in "
f"GenericInterfaceSymbol '{self.name}'")

def __str__(self):
return (f"{self.name}: {type(self).__name__}<{self.datatype}, "
f"routines={[rt.symbol.name for rt in self.routines]}>")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -----------------------------------------------------------------------------
# BSD 3-Clause License
#
# Copyright (c) 2023, Science and Technology Facilities Council.
# Copyright (c) 2023-2024, Science and Technology Facilities Council.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -71,6 +71,11 @@ def test_gis_constructor():
assert len(oak.routines) == 1
assert oak.routines[0].symbol is acorn
assert oak.routines[0].from_container is False
assert oak.container_routines == []
assert oak.external_routines == [acorn]
nut = RoutineSymbol("nut")
oak.routines.append(GenericInterfaceSymbol.RoutineInfo(nut, True))
assert oak.container_routines == [nut]


def test_gis_typedsymbol_keywords():
Expand Down Expand Up @@ -108,3 +113,24 @@ def test_gis_copy():
rsyms = [item.symbol for item in spinney.routines]
assert ash in rsyms
assert holly in rsyms


def test_gis_replace():
'''
Test the replace() method of GenericInterfaceSymbol.
'''
ash = RoutineSymbol("ash")
holly = RoutineSymbol("holly")
coppice = GenericInterfaceSymbol("coppice", [(ash, True), (holly, False)])
ivy = RoutineSymbol("ivy")
# Ivy is not yet a part of the interface.
with pytest.raises(ValueError) as err:
coppice.replace(ivy, holly)
assert ("RoutineSymbol 'ivy' not found in GenericInterfaceSymbol "
"'coppice'" in str(err.value))
coppice.replace(holly, ivy)
assert len(coppice.routines) == 2
# The replacement preserves the information on whether or not a routine
# originates from a Container.
assert coppice.external_routines == [ivy]
assert coppice.container_routines == [ash]

0 comments on commit 8bced83

Please sign in to comment.