Open sergisiso opened 1 year ago
Although we do now support these concepts, the fparser2 frontend is still ignoring them, e.g. Simon reports:
module m
contains
impure elemental subroutine s ! -> Issue 1: both "impure" and "elemental" disappear
...
I think this is a pretty small fix (though I'm not super comfortable with the fparser2 frontend). I added an else and print statement for now:
if prefix:
for child in prefix.children:
if isinstance(child, Fortran2003.Prefix_Spec):
if child.string not in SUPPORTED_ROUTINE_PREFIXES:
raise NotImplementedError(
f"Routine has unsupported prefix: {child.string}")
else:
print("SUPPORTED BUT WE DIDNT DO ANYTHIGN")
else:
base_type, _ = self._process_type_spec(routine, child)
and the SUPPORTED BUT WE DIDNT DO ANYTHING happens for impure and elemental. I can try to draft a fix together but I might need help putting together (unit) tests from someone more familiar with fparser2's frontend (unless you're actively working on this already @arporter )
Turns out (as usual with fparser2) i didn't understand it properly.
The above code is in subroutine handler, which I think would come up if we had a subroutine outside a module. I'm unclear what in the fparser2 frontend creates the routine symbol for such a scoping.
If we have a module containing it, then we have _process_routine_symbols
, which does pull out is_elemental or is_pure and add them to the routine symbol. This is not dropped by fparser (if a module is containing it) but actually by the fortran backend, which just has this code:
args = [symbol.name for symbol in node.symbol_table.argument_list]
suffix = ""
if node.return_symbol:
# This Routine has a return value and is therefore a Function
routine_type = "function"
if node.return_symbol.name.lower() != node.name.lower():
suffix = f" result({node.return_symbol.name})"
else:
routine_type = "subroutine"
result = f"{self._nindent}{routine_type} {node.name}("
result += ", ".join(args) + f"){suffix}\n"
The difficulty here is that the Routine doesn't seem to have any way to easily locate the symbol that belongs to it (You'd just have to search up the tree for any symbol tables with its name) in? In theory its possible to search for it with a = node.ancestor(Container).symbol_table.get_symbols()[node.name]
inside routine_node
, however I then get these print statements - the first is from fparser2.py (frontend) and the second is from fortran.py (backend) on the same symbol:
s: RoutineSymbol<NoType, pure=False, elemental=True>
s: RoutineSymbol<NoType, pure=unknown, elemental=unknown>
It looks like somewhere (I have no idea where) we lose this information. Its still in the symbol as of the end of _module_handler, so I think we lose it in the PSyIR somewhere.
This test will show this behaviour: Add this to line 1160 in backend/fortran.py (in routine_node) - it makes some other tests fail but not important for now
# Find RoutineSymbol
from psyclone.psyir.nodes.container import Container
a = node.ancestor(Container).symbol_table.get_symbols().get(node.name, None)
print(a)
Test code:
def test_elemental(parser, fortran_reader, fortran_writer):
code = '''
module mymod
contains
impure elemental subroutine s()
end subroutine
end module
'''
psyir = fortran_reader.psyir_from_source(code)
print(psyir.children[0].symbol_table)
print(fortran_writer(psyir))
assert False
My output here is:
Symbol Table of Container 'mymod':
----------------------------------
s: RoutineSymbol<NoType, pure=False, elemental=True>
Output:
s: RoutineSymbol<NoType, pure=unknown, elemental=unknown>
module mymod
implicit none
public
contains
subroutine s()
end subroutine s
end module mymod
So I correctly had the pure/impure/elemental information coming out of fparser (as long as the subroutine is contained within a module), but it gets lost - I think this is in copy, we can fix this information getting lost by adding a copy function to RoutineSymbol
:
def copy(self):
'''Create and return a copy of this object. Any references to the
original will not be affected so the copy will not be referred
to by any other object.
:returns: A symbol object with the same properties as this \
symbol object.
:rtype: :py:class:`psyclone.psyir.symbols.RoutineSymbol` '''
return type(self)(self.name, self.datatype, visibility=self.visibility, interface=self.interface, is_pure=self.is_pure, is_elemental=self.is_elemental)
I'll try to start working this into a branch tomorrow but I can't fix it for things outside of a module for now I think.
2147 is adding a flag that marks subroutines as elemental and pure.
Similarly it would be good to mark inquiry routines (that have arrays as arguments but the data of the array is not accessed).
This impacts the way the array2loop transformations treats them (currently there are manual exceptions for LBOUND, UBOUND, ...) and how the GPU offloading considers dependencies to their data (again we have manual exceptions)