Skip to content

Commit de7a132

Browse files
committed
compiler: fix buffering corner case such as interp
1 parent f2815a7 commit de7a132

2 files changed

Lines changed: 38 additions & 22 deletions

File tree

devito/ir/support/guards.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,14 @@ class GuardFactor(Guard, CondEq, Pickable):
6565

6666
__rargs__ = ('d',)
6767

68-
def __new__(cls, d, **kwargs):
68+
def __new__(cls, *args, **kwargs):
69+
if len(args) != 1:
70+
# Reconstruction with relational args (e.g. via sympy `_subs`): the
71+
# factor semantics no longer hold, so degrade to a plain relational
72+
base = CondNe if issubclass(cls, CondNe) else CondEq
73+
return base(*args, **kwargs)
74+
75+
d, = args
6976
assert d.is_Conditional
7077

7178
obj = super().__new__(cls, d.parent % d.symbolic_factor, 0)

devito/passes/clusters/buffering.py

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,11 @@ def _optimize(self, clusters, descriptors):
303303
processed.append(c)
304304
continue
305305

306-
key1 = lambda d: not d._defines & v.dim._defines # noqa: B023
306+
# Lift only along the buffer's own spatial Dimensions, not
307+
# unrelated ones (e.g. sparse points of an indirect read)
308+
key1 = lambda d: (not d._defines & v.dim._defines and # noqa: B023
309+
any(d._defines & bd._defines # noqa: B023
310+
for bd in v.bdims)) # noqa: B023
307311
dims = c.ispace.project(key1).itdims
308312
ispace = c.ispace.lift(dims, key0())
309313
processed.append(c.rebuild(ispace=ispace))
@@ -465,30 +469,31 @@ def itdims(self):
465469
def ispace(self):
466470
# The IterationSpace within which the buffer will be accessed
467471

468-
# NOTE: The `key` is to avoid Clusters including `f` but not directly
469-
# using it in an expression, such as HaloTouch Clusters
470-
def key(c):
471-
bufferdim = any(i in c.ispace.dimensions for i in self.bdims)
472-
xd_only = all(d._defines & self.xd._defines for d in c.ispace.dimensions)
473-
return bufferdim or xd_only
474-
475472
ispaces = set()
476473
for c in self.clusters:
477-
if not key(c):
478-
continue
479-
480-
# Skip wild clusters (e.g. HaloTouch Clusters)
474+
# Skip wild clusters (e.g. HaloTouch Clusters), which include `f`
475+
# but do not directly use it in an expression
481476
if c.is_wild:
482477
continue
483478

484-
# Iterations space and buffering dims
485-
edims = [d for d in self.bdims if d not in c.ispace.dimensions]
486-
if not edims:
487-
ispaces.add(c.ispace)
488-
else:
489-
# Add all missing buffering dimensions and reorder to
490-
# avoid duplicates with different ordering
491-
ispaces.add(c.ispace.insert(self.dim, edims).reorder())
479+
bufferdim = any(i in c.ispace.dimensions for i in self.bdims)
480+
xd_only = all(d._defines & self.xd._defines for d in c.ispace.dimensions)
481+
482+
if bufferdim or xd_only:
483+
# `c` iterates (at least some of) the buffer's spatial dims
484+
edims = [d for d in self.bdims if d not in c.ispace.dimensions]
485+
if not edims:
486+
ispaces.add(c.ispace)
487+
else:
488+
# Add all missing buffering dimensions and reorder to
489+
# avoid duplicates with different ordering
490+
ispaces.add(c.ispace.insert(self.dim, edims).reorder())
491+
elif ((self.f in c.scope.reads or self.f in c.scope.writes) and
492+
self.dim.root in c.ispace.dimensions):
493+
# `c` accesses `f` indirectly (e.g. interpolation), so it doesn't
494+
# iterate `bdims`; span the buffer's own Dimensions instead
495+
tispace = c.ispace.project(lambda i: i._defines & self.dim.root._defines)
496+
ispaces.add(tispace.insert(self.dim, list(self.bdims)))
492497

493498
if len(ispaces) > 1:
494499
# Best effort to make buffering work in the presence of multiple
@@ -609,7 +614,11 @@ def last_idx(self):
609614
mapper = {}
610615
func = vmax if self.is_forward_buffering else vmin
611616
for c in self.lastwrite + self.firstread:
612-
indices = extract_indices(self.f, self.dim, [c])
617+
# Consider all Clusters sharing `c`'s guards, so the leading edge is
618+
# found even when `f` is accessed at different offsets across them
619+
# (e.g. `f` and `f.forward` in separate Eqs)
620+
group = [c1 for c1 in self.clusters if c1.guards == c.guards]
621+
indices = extract_indices(self.f, self.dim, group)
613622
idx = func(*[Vector(i) for i in indices])[0]
614623
mapper[c] = idx
615624

0 commit comments

Comments
 (0)