ecmwf-ifs / loki

Freely programmable source-to-source translation for Fortran

Home Page:https://sites.ecmwf.int/docs/loki/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.