Repository: devitocodes/devito
Issue: Compilation fails on GPU backends

The following code snippet fails in Python with DEVITO_ARCH=nvc and DEVITO_LANGUAGE=openacc

Credits to @jkwashbourne 

```

import numpy as np
from devito import (Grid, Function, TimeFunction, Eq, Operator)
​
space_order = 4
nx,ny = 101,101
grid = Grid(extent=(1,1), shape=(nx,ny), origin=(0,0), dtype=np.float32)
x,y = grid.dimensions
​
f = Function(name='f', grid=grid, space_order=space_order)
g = TimeFunction(name='g', grid=grid, time_order=1, space_order=space_order)
t, x, y = g.dimensions
​
ymin = y.symbolic_min
​
eqns = []
eqns.append( Eq(g.forward, f + g.dx) )
​
for i in range(space_order//2):
    eqns.append( Eq(g[t+t.spacing, x, ymin-i], g[t+t.spacing, x, ymin+i]) )
​
op = Operator(eqns, name="OpSymbolicMinMFE")
​
op.apply(time_m=1, time_M=100)
```

Changed files:
devito/passes/clusters/misc.py, tests/test_fission.py, devito/ir/support/space.py

diff --git a/devito/ir/support/space.py b/devito/ir/support/space.py
index 26ca5c4e8..954dc3afa 100644
--- a/devito/ir/support/space.py
+++ b/devito/ir/support/space.py
@@ -540,6 +540,8 @@ class IterationInterval(object):
         return "%s%s" % (self.interval, self.direction)
 
     def __eq__(self, other):
+        if not isinstance(other, IterationInterval):
+            return False
         return self.direction is other.direction and self.interval == other.interval
 
     def __hash__(self):
diff --git a/devito/passes/clusters/misc.py b/devito/passes/clusters/misc.py
index 1d101c2bf..5d0517548 100644
--- a/devito/passes/clusters/misc.py
+++ b/devito/passes/clusters/misc.py
@@ -322,7 +322,14 @@ class Fission(Queue):
         for (it, guards), g in groupby(clusters, key=lambda c: self._key(c, prefix)):
             group = list(g)
 
-            if any(SEQUENTIAL in c.properties[it.dim] for c in group) or guards:
+            try:
+                test0 = any(SEQUENTIAL in c.properties[it.dim] for c in group)
+            except AttributeError:
+                # `it` is None because `c`'s IterationSpace has no `d` Dimension,
+                # hence `key = (it, guards) = (None, guards)`
+                test0 = True
+
+            if test0 or guards:
                 # Heuristic: no gain from fissioning if unable to ultimately
                 # increase the number of collapsable iteration spaces, hence give up
                 processed.extend(group)
diff --git a/tests/test_fission.py b/tests/test_fission.py
index 0c66a06af..2e67d6cf2 100644
--- a/tests/test_fission.py
+++ b/tests/test_fission.py
@@ -1,3 +1,5 @@
+import numpy as np
+
 from conftest import assert_structure
 from devito import (Eq, Inc, Grid, Function, TimeFunction, SubDimension, SubDomain,
                     Operator, solve)
@@ -94,3 +96,32 @@ def test_fission_partial():
     op = Operator(eqns, opt='fission')
 
     assert_structure(op, ['t,x,yl', 't,x,yr', 't,x,y'], 't,x,yl,yr,x,y')
+
+
+def test_issue_1921():
+    space_order = 4
+    grid = Grid(shape=(8, 8), dtype=np.int32)
+
+    f = Function(name='f', grid=grid, space_order=space_order)
+    g = TimeFunction(name='g', grid=grid, space_order=space_order)
+    g1 = TimeFunction(name='g', grid=grid, space_order=space_order)
+
+    f.data[:] = np.arange(8*8).reshape((8, 8))
+
+    t, x, y = g.dimensions
+    ymin = y.symbolic_min
+
+    eqns = []
+    eqns.append(Eq(g.forward, f + g))
+    for i in range(space_order//2):
+        eqns.append(Eq(g[t+t.spacing, x, ymin-i], g[t+t.spacing, x, ymin+i]))
+
+    op0 = Operator(eqns)
+    op1 = Operator(eqns, opt='fission')
+
+    assert_structure(op1, ['t,x,y', 't,x'], 't,x,y,x')
+
+    op0.apply(time_m=1, time_M=5)
+    op1.apply(time_m=1, time_M=5, g=g1)
+
+    assert np.all(g.data == g1.data)