Combination of trivial SubstituteExpressions with Transformer fails
reuterbal opened this issue · comments
The following fails:
fcode_kernel = """
SUBROUTINE compute_column(start, end, nlon, nz, q)
INTEGER, INTENT(IN) :: start, end
INTEGER, INTENT(IN) :: nlon, nz
REAL, INTENT(INOUT) :: q(nlon,nz)
INTEGER :: jl
DO JL = START, END
Q(JL, NZ) = Q(JL, NZ) * 0.5
END DO
DO JL = START, END
Q(JL, NZ) = Q(JL, NZ) * 0.5
END DO
END SUBROUTINE compute_column
"""
from loki import FP, Subroutine, FindNodes, Loop, Transformer, SubstituteExpressions
frontend = FP
kernel = Subroutine.from_source(fcode_kernel, frontend=frontend)
kernel.body = SubstituteExpressions({}).visit(kernel.body)
loops = FindNodes(Loop).visit(kernel.body)
kernel.body = Transformer({l: l.body for l in loops}).visit(kernel.body)
with an error messages as follow:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/nabr/loki/main/loki/visitors/transform.py", line 237, in visit
obj = super().visit(o, *args, **kwargs)
File "/home/nabr/loki/main/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/nabr/loki/main/loki/visitors/transform.py", line 174, in visit_Node
rebuilt = tuple(self.visit(i, **kwargs) for i in o.children)
File "/home/nabr/loki/main/loki/visitors/transform.py", line 174, in <genexpr>
rebuilt = tuple(self.visit(i, **kwargs) for i in o.children)
File "/home/nabr/loki/main/loki/visitors/transform.py", line 237, in visit
obj = super().visit(o, *args, **kwargs)
File "/home/nabr/loki/main/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/nabr/loki/main/loki/visitors/transform.py", line 149, in visit_tuple
visited = tuple(self.visit(i, **kwargs) for i in o)
File "/home/nabr/loki/main/loki/visitors/transform.py", line 149, in <genexpr>
visited = tuple(self.visit(i, **kwargs) for i in o)
File "/home/nabr/loki/main/loki/visitors/transform.py", line 237, in visit
obj = super().visit(o, *args, **kwargs)
File "/home/nabr/loki/main/loki/visitors/visitor.py", line 124, in visit
return meth(o, *args, **kwargs)
File "/home/nabr/loki/main/loki/visitors/transform.py", line 172, in visit_Node
return handle._rebuild(**handle.args)
AttributeError: 'tuple' object has no attribute '_rebuild'
The issue is in Transformer._inject_tuple_mapping
. Since the loop is mapped to a tuple, this replacement should have been performed in there. However, due to the previous call to SubstituteExpressions
, the source
property has been invalidated on the loop nodes, yielding absolutely identical loop nodes, which appear in the same tuple. (The error disappears if invalidate_source=False
is used in SubstituteExpressions
).
The problem arises now due to the fact, that only the first occurence of that match is replaced, and the subsequent occurence is replaced via the usual node2node replacement mechanism, which triggers a rebuild on the replacement node - which of course is not defined for a tuple.