Add support for `FORALL`
quepas opened this issue · comments
When a FORALL statement is inside IF-ELSE construct Loki is not able to build the AST. I have prepared three Fortran examples, one not producing an error and two producing two different errors.
Tested versions:
0.1.4.dev151+g45e51fd
v0.1.2
No error
subroutine forall_no_error_example()
integer, parameter :: n = 10
real :: array(n)
integer :: i
forall(i = 1:n) array(i) = 1.0
end subroutine
Error 1
subroutine forall_error_1_example()
integer, parameter :: n = 10
real :: array(n)
integer :: i
if (n > 5) then
forall(i = 1:n) array(i) = 1.0
endif
end subroutine
Produces error:
>>> s1 = Sourcefile.from_file("forall_error_1.f90")
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Stmt'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Header'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Triplet_Spec_List'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Triplet_Spec'>
[Loki::Sourcefile] Constructed from forall_error_1.f90 in 0.05s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/sourcefile.py", line 134, in from_file
return cls.from_fparser(source, filepath, definitions=definitions)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/sourcefile.py", line 256, in from_fparser
return cls._from_fparser_ast(path=filepath, ast=ast, definitions=definitions,
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/sourcefile.py", line 265, in _from_fparser_ast
ir = parse_fparser_ast(ast, pp_info=pp_info, definitions=definitions, raw_source=raw_source)
File "/usr/lib/python3.10/contextlib.py", line 79, in inner
return func(*args, **kwds)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 106, in parse_fparser_ast
_ir = FParser2IR(raw_source=raw_source, definitions=definitions, pp_info=pp_info, scope=scope).visit(ast)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in visit_Specification_Part
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/tools/util.py", line 150, in flatten
for el in l:
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in <genexpr>
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 1753, in visit_Subroutine_Subprogram
body = self.visit(body_ast, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in visit_Specification_Part
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/tools/util.py", line 150, in flatten
for el in l:
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in <genexpr>
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 2132, in visit_If_Construct
node = ir.Conditional(condition=conditions[-1], body=body, else_body=as_tuple(else_body),
File "pydantic/dataclasses.py", line 286, in pydantic.dataclasses._add_pydantic_validation_attributes.handle_extra_init
def __init__(self, default, default_factory, init, repr, hash, compare,
File "<string>", line 11, in __init__
File "pydantic/dataclasses.py", line 305, in pydantic.dataclasses._add_pydantic_validation_attributes.new_post_init
f'name={self.name!r},'
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/ir.py", line 597, in __post_init__
assert all(isinstance(c, Node) for c in self.body) # pylint: disable=not-an-iterable
AssertionError
Error 2
subroutine forall_error_2_example()
integer, parameter :: n = 10
real :: array(n)
integer :: i
if (n > 5) then
else
forall(i = 1:n) array(i) = 1.0
endif
end subroutine
Produces error:
>>> s1 = Sourcefile.from_file("forall_error_2.f90")
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Stmt'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Header'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Triplet_Spec_List'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Triplet_Spec'>
[Loki::Sourcefile] Constructed from forall_error_2.f90 in 0.05s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/sourcefile.py", line 134, in from_file
return cls.from_fparser(source, filepath, definitions=definitions)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/sourcefile.py", line 256, in from_fparser
return cls._from_fparser_ast(path=filepath, ast=ast, definitions=definitions,
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/sourcefile.py", line 265, in _from_fparser_ast
ir = parse_fparser_ast(ast, pp_info=pp_info, definitions=definitions, raw_source=raw_source)
File "/usr/lib/python3.10/contextlib.py", line 79, in inner
return func(*args, **kwds)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 106, in parse_fparser_ast
_ir = FParser2IR(raw_source=raw_source, definitions=definitions, pp_info=pp_info, scope=scope).visit(ast)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in visit_Specification_Part
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/tools/util.py", line 150, in flatten
for el in l:
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in <genexpr>
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 1753, in visit_Subroutine_Subprogram
body = self.visit(body_ast, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in visit_Specification_Part
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/tools/util.py", line 150, in flatten
for el in l:
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 328, in <genexpr>
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/frontend/fparser.py", line 2132, in visit_If_Construct
node = ir.Conditional(condition=conditions[-1], body=body, else_body=as_tuple(else_body),
File "pydantic/dataclasses.py", line 286, in pydantic.dataclasses._add_pydantic_validation_attributes.handle_extra_init
def __init__(self, default, default_factory, init, repr, hash, compare,
File "<string>", line 11, in __init__
File "pydantic/dataclasses.py", line 305, in pydantic.dataclasses._add_pydantic_validation_attributes.new_post_init
f'name={self.name!r},'
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/ir.py", line 592, in __post_init__
super().__post_init__()
File "pydantic/dataclasses.py", line 305, in pydantic.dataclasses._add_pydantic_validation_attributes.new_post_init
f'name={self.name!r},'
File "/home/quepas/Research/AWACA/source2source/PaintingCode/venv/lib/python3.10/site-packages/loki/ir.py", line 236, in __post_init__
super().__post_init__()
File "pydantic/dataclasses.py", line 308, in pydantic.dataclasses._add_pydantic_validation_attributes.new_post_init
f'default_factory={self.default_factory!r},'
File "pydantic/dataclasses.py", line 425, in pydantic.dataclasses._dataclass_validate_values
pydantic.error_wrappers.ValidationError: 3 validation errors for Conditional
else_body -> 0
instance of Node, tuple or dict expected (type=type_error.dataclass; class_name=Node)
else_body -> 1
instance of Node, tuple or dict expected (type=type_error.dataclass; class_name=Node)
else_body -> 2
instance of Node, tuple or dict expected (type=type_error.dataclass; class_name=Node)
btw. great project! :)
Hi,
apologies for the delay in acknowledging this and thank you very much for bringing this to our attention.
Loki currently doesn't have any support for forall
. Even the "no error" example you provided produces a few warnings for me:
>>> source = Sourcefile.from_file('forall_no_error.f90.txt')
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Stmt'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Header'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Triplet_Spec_List'>
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Triplet_Spec'>
[Loki::Sourcefile] Constructed from forall_no_error.f90.txt in 0.05s
Although it succeeds in producing an internal representation, it's not the correct one if you inspect the Fortran that is generated from it:
>>> print(source.to_fortran())
SUBROUTINE forall_no_error_example ()
INTEGER, PARAMETER :: n = 10
REAL :: array(n)
INTEGER :: i
i
1
n
array(i) = 1.0
END SUBROUTINE forall_no_error_example
Note that we intentionally don't fail on unsupported node types by default to allow for a more graceful handling in bulk processing. However, a "strict" frontend mode can be enabled by setting LOKI_FRONTEND_STRICT_MODE=1
:
$ LOKI_FRONTEND_STRICT_MODE=1 python -c "from loki import Sourcefile; Sourcefile.from_file('forall_no_error.f90.txt')"
No specific handler for node type <class 'fparser.two.Fortran2003.Forall_Stmt'>
[Loki::Sourcefile] Constructed from forall_no_error.f90.txt in 0.03s
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/sourcefile.py", line 134, in from_file
return cls.from_fparser(source, filepath, definitions=definitions)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/sourcefile.py", line 256, in from_fparser
return cls._from_fparser_ast(path=filepath, ast=ast, definitions=definitions,
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/sourcefile.py", line 265, in _from_fparser_ast
ir = parse_fparser_ast(ast, pp_info=pp_info, definitions=definitions, raw_source=raw_source)
File "/usr/local/apps/python3/3.8.8-01/lib/python3.8/contextlib.py", line 75, in inner
return func(*args, **kwds)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 106, in parse_fparser_ast
_ir = FParser2IR(raw_source=raw_source, definitions=definitions, pp_info=pp_info, scope=scope).visit(ast)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 328, in visit_Specification_Part
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/tools/util.py", line 150, in flatten
for el in l:
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 328, in <genexpr>
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 1753, in visit_Subroutine_Subprogram
body = self.visit(body_ast, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 328, in visit_Specification_Part
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/tools/util.py", line 150, in flatten
for el in l:
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 328, in <genexpr>
children = as_tuple(flatten(self.visit(c, **kwargs) for c in o.children))
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 301, in visit
return super().visit(o, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 2746, in visit_Base
self.warn_or_fail(f'No specific handler for node type {o.__class__}')
File "/etc/ecmwf/nfs/dh1_home_a/nabr/loki/main/loki/frontend/fparser.py", line 263, in warn_or_fail
raise NotImplementedError
NotImplementedError
There is currently no timeline as to when forall
is planned to be added, since we integrate newer Fortran features only on a best-effort basis when they are needed. However, we would much welcome the addition of forall to the Loki IR, which likely should be implemented as an extension of the Loop
node in ir.py
.
@reuterbal Thanks for your response! I am starting to work more and more with Loki, so it is quite possible that I will be able to contribute soon.
I attempted to implement the support of FORALL here #210