Skip to content

Commit

Permalink
Improve representation of procedure declarations with implicit interface
Browse files Browse the repository at this point in the history
  • Loading branch information
reuterbal committed Oct 14, 2024
1 parent 98ee8ca commit c71c308
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 13 deletions.
16 changes: 16 additions & 0 deletions loki/backend/tests/test_fgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,27 @@ def test_fgen_procedure_pointer(frontend, use_module, tmp_path):
source = Sourcefile.from_source(fcode, frontend=frontend, definitions=definitions, xmods=[tmp_path])
routine = source['spcmnew']
ptr = routine.variable_map['spnsiptr']
func = routine.variable_map['func']

# Make sure we always have procedure type as dtype for the declared pointers
assert isinstance(ptr.type.dtype, ProcedureType)
assert isinstance(func.type.dtype, ProcedureType)

# We should have the inter-procedural annotation in place if the module
# definition was provided
if use_module:
assert ptr.type.dtype.procedure is module['spnsi'].body[0]
else:
assert ptr.type.dtype.procedure == BasicType.DEFERRED

# With an implicit interface routine like this, we will never have
# procedure information in place
assert func.type.dtype.procedure == BasicType.DEFERRED
assert func.type.dtype.return_type.dtype == BasicType.REAL

# Check the interfaces declared on the variable declarations
assert tuple(decl.interface for decl in routine.declarations) == ('SPNSI', BasicType.REAL)

# Ensure that the fgen backend does the right thing
assert 'procedure(spnsi), pointer :: spnsiptr' in source.to_fortran().lower()
assert 'procedure(real), pointer, intent(out) :: func' in source.to_fortran().lower()
2 changes: 1 addition & 1 deletion loki/frontend/ofp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ def visit_declaration(self, o, **kwargs):
interface = _type.dtype
for var in symbols:
dtype = ProcedureType(var.name, is_function=True, return_type=_type)
scope.symbol_attrs[var.name] = var.type.clone(dtype=dtype)
scope.symbol_attrs[var.name] = _type.clone(dtype=dtype)

# Rescope variables so they know their type
symbols = tuple(var.rescope(scope=scope) for var in symbols)
Expand Down
33 changes: 21 additions & 12 deletions loki/frontend/omni.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,9 @@ def visit_varDecl(self, o, **kwargs):
name = o.find('name')
variable = self.visit(name, **kwargs)

interface = None
scope = kwargs['scope']

# Create the declared type
if name.attrib['type'] in self._omni_types:
# Intrinsic scalar type
Expand All @@ -571,12 +574,19 @@ def visit_varDecl(self, o, **kwargs):
variable.name, is_function=_type.dtype.is_function, return_type=_type.dtype.return_type
)
_type = _type.clone(dtype=dtype)
interface = dtype.return_type.dtype

if variable != kwargs['scope'].name:
if variable != scope.name:
# Instantiate the symbol representing the procedure in the current scope to create
# relevant symbol table entries, and then extract the dtype
dtype = kwargs['scope'].Variable(name=_type.dtype.name).type.dtype
_type = _type.clone(dtype=dtype)
try:
symbol_scope = scope.get_symbol_scope(_type.dtype.name)
interface = symbol_scope.Variable(name=_type.dtype.name)
_type = _type.clone(dtype=interface.type.dtype)
except AttributeError:
# Interface symbol could not be found
pass

elif _type.dtype.return_type is not None:
# This is the declaration of the return type inside a function, which is
# why we restore the return_type
Expand All @@ -593,7 +603,6 @@ def visit_varDecl(self, o, **kwargs):
else:
raise ValueError

scope = kwargs['scope']
if o.find('value') is not None:
_type = _type.clone(initial=AttachScopesMapper()(self.visit(o.find('value'), **kwargs), scope=scope))
if _type.kind is not None:
Expand All @@ -604,14 +613,14 @@ def visit_varDecl(self, o, **kwargs):

if isinstance(_type.dtype, ProcedureType):
# This is actually a function or subroutine (EXTERNAL or PROCEDURE declaration)
if _type.external:
return ir.ProcedureDeclaration(symbols=(variable,), external=True, source=kwargs['source'])
if _type.dtype.name == variable and _type.dtype.is_function:
return ir.ProcedureDeclaration(
symbols=(variable,), interface=_type.dtype.return_type.dtype, source=kwargs['source']
)
interface = sym.Variable(name=_type.dtype.name, scope=scope.get_symbol_scope(_type.dtype.name))
return ir.ProcedureDeclaration(symbols=(variable,), interface=interface, source=kwargs['source'])
# if _type.external:
# return ir.ProcedureDeclaration(symbols=(variable,), external=True, source=kwargs['source'])
# if _type.dtype.name == variable and _type.dtype.is_function:
# return ir.ProcedureDeclaration(
# symbols=(variable,), interface=_type.dtype.return_type.dtype, source=kwargs['source']
# )
# interface = sym.Variable(name=_type.dtype.name, scope=scope.get_symbol_scope(_type.dtype.name))
return ir.ProcedureDeclaration(symbols=(variable,), interface=interface, external=_type.external or False, source=kwargs['source'])

Check failure on line 623 in loki/frontend/omni.py

View workflow job for this annotation

GitHub Actions / code checks (3.11)

C0301: Line too long (143/120) (line-too-long)

return ir.VariableDeclaration(symbols=(variable,), source=kwargs['source'])

Expand Down

0 comments on commit c71c308

Please sign in to comment.