Skip to content

Commit

Permalink
#2642 Edits w.r.t. Andy's review
Browse files Browse the repository at this point in the history
  • Loading branch information
JulienRemy committed Dec 11, 2024
1 parent 706bffc commit b72336b
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 166 deletions.
52 changes: 26 additions & 26 deletions src/psyclone/domain/lfric/kernel/lfric_kernel_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,40 +44,40 @@
from fparser.two.utils import walk, get_child

from psyclone.domain.lfric import LFRicConstants
from psyclone.domain.lfric.kernel.columnwise_operator_arg_metadata import \
ColumnwiseOperatorArgMetadata
from psyclone.domain.lfric.kernel.columnwise_operator_arg_metadata import (
ColumnwiseOperatorArgMetadata)
from psyclone.domain.lfric.kernel.field_arg_metadata import FieldArgMetadata
from psyclone.domain.lfric.kernel.field_vector_arg_metadata import \
FieldVectorArgMetadata
from psyclone.domain.lfric.kernel.inter_grid_arg_metadata import \
InterGridArgMetadata
from psyclone.domain.lfric.kernel.inter_grid_vector_arg_metadata import \
InterGridVectorArgMetadata
from psyclone.domain.lfric.kernel.operator_arg_metadata import \
OperatorArgMetadata
from psyclone.domain.lfric.kernel.field_vector_arg_metadata import (
FieldVectorArgMetadata)
from psyclone.domain.lfric.kernel.inter_grid_arg_metadata import (
InterGridArgMetadata)
from psyclone.domain.lfric.kernel.inter_grid_vector_arg_metadata import (
InterGridVectorArgMetadata)
from psyclone.domain.lfric.kernel.operator_arg_metadata import (
OperatorArgMetadata)
from psyclone.domain.lfric.kernel.common_metadata import CommonMetadata
from psyclone.domain.lfric.kernel.common_meta_arg_metadata import \
CommonMetaArgMetadata
from psyclone.domain.lfric.kernel.evaluator_targets_metadata import \
EvaluatorTargetsMetadata
from psyclone.domain.lfric.kernel.meta_args_metadata import \
MetaArgsMetadata
from psyclone.domain.lfric.kernel.meta_funcs_metadata import \
MetaFuncsMetadata
from psyclone.domain.lfric.kernel.meta_mesh_metadata import \
MetaMeshMetadata
from psyclone.domain.lfric.kernel.meta_ref_element_metadata import \
MetaRefElementMetadata
from psyclone.domain.lfric.kernel.operates_on_metadata import \
OperatesOnMetadata
from psyclone.domain.lfric.kernel.common_meta_arg_metadata import (
CommonMetaArgMetadata)
from psyclone.domain.lfric.kernel.evaluator_targets_metadata import (
EvaluatorTargetsMetadata)
from psyclone.domain.lfric.kernel.meta_args_metadata import (
MetaArgsMetadata)
from psyclone.domain.lfric.kernel.meta_funcs_metadata import (
MetaFuncsMetadata)
from psyclone.domain.lfric.kernel.meta_mesh_metadata import (
MetaMeshMetadata)
from psyclone.domain.lfric.kernel.meta_ref_element_metadata import (
MetaRefElementMetadata)
from psyclone.domain.lfric.kernel.operates_on_metadata import (
OperatesOnMetadata)
from psyclone.domain.lfric.kernel.scalar_arg_metadata import ScalarArgMetadata
from psyclone.domain.lfric.kernel.shapes_metadata import ShapesMetadata
from psyclone.errors import InternalError
from psyclone.parse.utils import ParseError
from psyclone.psyir.frontend.fortran import FortranReader
from psyclone.psyir.backend.fortran import FortranWriter
from psyclone.psyir.symbols import DataTypeSymbol, UnsupportedFortranType, \
StructureType
from psyclone.psyir.symbols import (DataTypeSymbol, UnsupportedFortranType,
StructureType)

# pylint: disable=too-many-lines
# pylint: disable=too-many-instance-attributes
Expand Down
3 changes: 2 additions & 1 deletion src/psyclone/psyGen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1792,7 +1792,8 @@ def _rename_psyir(self, suffix):
elif (procedure_component.initial_value is not None
and (procedure_component.initial_value.name.lower()
== orig_kern_name.lower())):
new_kernel_symbol = RoutineSymbol(new_kern_name)
new_kernel_symbol = container_table.lookup(

Check warning on line 1795 in src/psyclone/psyGen.py

View check run for this annotation

Codecov / codecov/patch

src/psyclone/psyGen.py#L1795

Added line #L1795 was not covered by tests
new_kern_name)
new_procedure_component = \

Check warning on line 1797 in src/psyclone/psyGen.py

View check run for this annotation

Codecov / codecov/patch

src/psyclone/psyGen.py#L1797

Added line #L1797 was not covered by tests
StructureType.ComponentType(procedure_component
.name,
Expand Down
2 changes: 1 addition & 1 deletion src/psyclone/psyad/domain/lfric/lfric_adjoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
from psyclone.psyad import AdjointVisitor
from psyclone.psyad.domain.common import create_adjoint_name
from psyclone.psyir.nodes import Routine
from psyclone.psyir.symbols import (ContainerSymbol, StructureType)
from psyclone.psyir.symbols import ContainerSymbol, StructureType
from psyclone.psyir.symbols.symbol import ArgumentInterface, ImportInterface


Expand Down
7 changes: 4 additions & 3 deletions src/psyclone/psyir/backend/fortran.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,9 @@ def gen_decls(self, symbol_table, is_module_scope=False):
# We ignore all symbols with a PreprocessorInterface
if isinstance(sym.interface, PreprocessorInterface):
all_symbols.remove(sym)
# We remove the '*' symbol used in 'class(*) :: var'
if sym.name == "*":
all_symbols.remove(sym)

# If the symbol table contains any symbols with an
# UnresolvedInterface interface (they are not explicitly
Expand All @@ -1010,9 +1013,7 @@ def gen_decls(self, symbol_table, is_module_scope=False):
unresolved_symbols = []
for sym in all_symbols[:]:
if isinstance(sym.interface, UnresolvedInterface):
# Explicitly deal with '*' as in 'class(*) :: var'
if sym.name != "*":
unresolved_symbols.append(sym)
unresolved_symbols.append(sym)
all_symbols.remove(sym)
try:
internal_interface_symbol = symbol_table.lookup(
Expand Down
204 changes: 117 additions & 87 deletions src/psyclone/psyir/frontend/fparser2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,8 @@ def _process_type_spec(self, parent, type_spec):
if isinstance(type_spec.items[1], Fortran2003.Type_Name):
type_name = str(type_spec.items[1].string).lower()
else:
# If we are processing a `class(*) :: var` declaration, the
# type name is not a Type_Name but a string.
type_name = type_spec.items[1].lower()
# Do we already have a Symbol for this derived type?
type_symbol = _find_or_create_unresolved_symbol(parent, type_name)
Expand Down Expand Up @@ -1986,85 +1988,36 @@ def _process_derived_type_decln(self, parent, decl, visibility_map):
derived_type_stmt = decl.children[0]
type_attr_spec_list = walk(derived_type_stmt,
Fortran2003.Type_Attr_Spec)
if type_attr_spec_list:
for type_attr_spec in type_attr_spec_list:
# Deal with 'EXTENDS(parent_type)'.
if type_attr_spec.items[0] == "EXTENDS":
extends_name = type_attr_spec.items[1].string
# Look up the extended type in the symbol table
# and specialise the symbol if needed.
if extends_name in parent.symbol_table:
extends_symbol = parent.symbol_table.lookup(
extends_name)
if type(extends_symbol) is Symbol:
extends_symbol.specialise(DataTypeSymbol)
extends_symbol.datatype = StructureType()
# If it is not in the symbol table, create a new
# DataTypeSymbol for it.
else:
extends_symbol = DataTypeSymbol(extends_name,
StructureType())
# Set it as the extended type of the new type.
dtype.extends = extends_symbol

for type_attr_spec in type_attr_spec_list:
# Deal with 'EXTENDS(parent_type)'.
if type_attr_spec.items[0] == "EXTENDS":
extends_name = type_attr_spec.items[1].string
# Look up the extended type in the symbol table
# and specialise the symbol if needed.
extends_symbol = parent.symbol_table.lookup(
extends_name, otherwise=None)
if extends_symbol:
# pylint: disable=unidiomatic-typecheck
if type(extends_symbol) is Symbol:
extends_symbol.specialise(DataTypeSymbol)
extends_symbol.datatype = StructureType()
# If it is not in the symbol table, create a new
# DataTypeSymbol for it.
# NOTE: this should *not* be added to the symbol table
# as it might be defined somewhere else if it was imported.
else:
raise NotImplementedError("Derived-type definition "
"contains unsupported "
"attributes.")
extends_symbol = DataTypeSymbol(extends_name,
StructureType())
# Set it as the extended type of the new type.
dtype.extends = extends_symbol
else:
raise NotImplementedError("Derived-type definition "
"contains unsupported "
"attributes.")

# We support derived-type definitions with a CONTAINS section.
contains_blocks = walk(decl, Fortran2003.Type_Bound_Procedure_Part)
if contains_blocks:
# Get it.
contains = contains_blocks[0]
# Get all procedures in the CONTAINS section.
procedures = walk(contains, Fortran2003.Specific_Binding)
if len(procedures) > 0:
# Process each procedure.
for procedure in procedures:
supported = True
# We do not support interfaces.
if procedure.items[0] is not None:
supported = False
# We do not support 'pass', 'nopass', 'deferred', etc.
if procedure.items[1] is not None:
supported = False

# Get the name, look it up in the symbol table and
# get its datatype or create it if it does not exist.
procedure_name = procedure.items[3].string
if procedure_name in parent.symbol_table and supported:
procedure_symbol = parent.symbol_table.\
lookup(procedure_name)
procedure_datatype = procedure_symbol.datatype
else:
procedure_datatype = UnsupportedFortranType(
procedure.string,
None)

# Get the visibility of the procedure.
procedure_vis = dtype_symbol_vis
if procedure.items[1] is not None:
access_spec = walk(procedure.items[1],
Fortran2003.Access_Spec)
if access_spec:
procedure_vis = _process_access_spec(
access_spec[0])

# Deal with the optional initial value.
if procedure.items[4] is not None:
initial_value_name = procedure.items[4].string
initial_value_symbol = RoutineSymbol(
initial_value_name,
UnresolvedType())
initial_value = Reference(initial_value_symbol)
else:
initial_value = None

# Add this procedure as a component of the derived type
dtype.add_procedure_component(procedure_name,
procedure_datatype,
procedure_vis,
initial_value)
self._process_derived_type_contains_block(parent, decl, tsymbol)

# Re-use the existing code for processing symbols. This needs to
# be able to find any symbols declared in an outer scope but
Expand Down Expand Up @@ -2098,6 +2051,82 @@ def _process_derived_type_decln(self, parent, decl, visibility_map):
tsymbol.datatype = UnsupportedFortranType(str(decl))
tsymbol.interface = UnknownInterface()

def _process_derived_type_contains_block(self, parent, decl, tsymbol):
'''
Process the supplied fparser2 parse tree for a the CONTAINS section of
a derived-type declaration to add any procedures to the DataTypeSymbol.
:param parent: PSyIR node in which to insert the symbols found.
:type parent: :py:class:`psyclone.psyir.nodes.ScopingNode`
:param decl: fparser2 parse tree of declaration to process.
:type decl: :py:class:`fparser.two.Fortran2003.Type_Declaration_Stmt`
:param tsymbol: the DataTypeSymbol representing the derived-type.
:type tsymbol: :py:class:`psyclone.psyir.symbols.DataTypeSymbol`
:returns: None
'''

contains_blocks = walk(decl, Fortran2003.Type_Bound_Procedure_Part)
if contains_blocks:
# Get it.
contains = contains_blocks[0]
# Get all procedures in the CONTAINS section.
procedures = walk(contains, Fortran2003.Specific_Binding)

# Process each procedure.
for procedure in procedures:
supported = True
# We do not support interfaces.
if procedure.items[0] is not None:
supported = False
# We do not support 'pass', 'nopass', 'deferred', etc.
if procedure.items[1] is not None:
supported = False

# Get the name, look it up in the symbol table and
# get its datatype or create it if it does not exist.
procedure_name = procedure.items[3].string
procedure_symbol = parent.symbol_table.lookup(
procedure_name,
otherwise=None)
if procedure_symbol and supported:
procedure_datatype = procedure_symbol.datatype
else:
procedure_datatype = UnsupportedFortranType(
procedure.string,
None)

# Get the visibility of the procedure.
procedure_vis = tsymbol.visibility
if procedure.items[1] is not None:
access_spec = walk(procedure.items[1],
Fortran2003.Access_Spec)
if access_spec:
procedure_vis = _process_access_spec(
access_spec[0])

# Deal with the optional initial value.
# This could be, e.g., `null` in `procedure, name => null()` or
# `testkern_code` in `procedure :: code => testkern_code`
if procedure.items[4] is not None:
initial_value_name = procedure.items[4].string
initial_value_symbol = parent.symbol_table.lookup(
initial_value_name, otherwise=None)
if not initial_value_symbol:
initial_value_symbol = RoutineSymbol(
initial_value_name,
UnresolvedType())
initial_value = Reference(initial_value_symbol)
else:
initial_value = None

# Add this procedure as a component of the derived type
tsymbol.datatype.add_procedure_component(procedure_name,
procedure_datatype,
procedure_vis,
initial_value)

def _get_partial_datatype(self, node, scope, visibility_map):
'''Try to obtain partial datatype information from node by removing
any unsupported properties in the declaration.
Expand Down Expand Up @@ -3340,8 +3369,6 @@ def _add_target_attribute(var_name, table):
'''
# pylint: disable=import-outside-toplevel
# Import here to avoid circular dependencies.
from psyclone.psyir.backend.fortran import FortranWriter

try:
symbol = table.lookup(var_name)
Expand All @@ -3355,21 +3382,24 @@ def _add_target_attribute(var_name, table):
f"be resolved and a DataSymbol")

datatype = symbol.datatype
# If this is of UnsupportedFortranType,
# create Fortran text for the supplied datatype from the
# supplied UnsupportedFortranType text, then parse this into an
# fparser2 tree and store the fparser2 representation of the
# datatype in type_decl_stmt.
if isinstance(datatype, UnsupportedFortranType):
# If this is of UnsupportedFortranType,
# create Fortran text for the supplied datatype from the
# supplied UnsupportedFortranType text, then parse this into an
# fparser2 tree and store the fparser2 representation of the
# datatype in type_decl_stmt.
dummy_code = (
f"subroutine dummy()\n"
f" {datatype.declaration}\n"
f"end subroutine\n")
# If not, this is a supported derived type so we can use the
# backend to generate the Fortran text for the datatype.
# But we need to turn its datatype into an UnsupportedFortranType
# in order to add the 'TARGET' attribute to the declaration.
else:
# If not, this is a supported derived type so we can use the
# backend to generate the Fortran text for the datatype.
# But we need to turn its datatype into an UnsupportedFortranType
# in order to add the 'TARGET' attribute to the declaration.

# Import here to avoid circular dependencies.
from psyclone.psyir.backend.fortran import FortranWriter
dummy_code = (
f"subroutine dummy()\n"
f" {FortranWriter().gen_vardecl(symbol)}\n"
Expand Down
4 changes: 3 additions & 1 deletion src/psyclone/psyir/symbols/data_type_symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class DataTypeSymbol(Symbol):
:type visibility: :py:class:`psyclone.psyir.symbols.Symbol.Visibility`
:param interface: the interface to this symbol.
:type interface: :py:class:`psyclone.psyir.symbols.SymbolInterface`
:param bool is_class: whether this symbol is used in a 'class' or 'type'
declaration.
'''
def __init__(self, name, datatype,
Expand Down Expand Up @@ -125,7 +127,7 @@ def is_class(self):
def is_class(self, value):
''' Setter for DataTypeSymbol is_class.
:param bool value: whether this DataTypeSymbol is a 'class' \
:param bool value: whether this DataTypeSymbol is a 'class'
declaration, i.e. not a 'type' one.
:raises TypeError: if value is not a bool.
Expand Down
Loading

0 comments on commit b72336b

Please sign in to comment.