From fa680a37ff0e381bc3222087b72b35d462f9bdec Mon Sep 17 00:00:00 2001 From: Fabio Luporini Date: Wed, 15 Jul 2026 13:23:50 +0100 Subject: [PATCH 1/3] compiler: Simplify fission --- devito/passes/clusters/misc.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/devito/passes/clusters/misc.py b/devito/passes/clusters/misc.py index 68b982eedc..0c53ec6378 100644 --- a/devito/passes/clusters/misc.py +++ b/devito/passes/clusters/misc.py @@ -1,10 +1,10 @@ from itertools import groupby, product from devito.ir.clusters import Queue, cluster_pass -from devito.ir.support import SEPARABLE, SEQUENTIAL, Scope +from devito.ir.support import SEPARABLE, Scope from devito.passes.clusters.utils import in_critical_region from devito.symbolics import pow_to_mul -from devito.tools import Stamp, flatten, frozendict, timed_pass +from devito.tools import Stamp, flatten, timed_pass from devito.types import Hyperplane __all__ = ['Lift', 'fission', 'optimize_hyperplanes', 'optimize_pows'] @@ -123,7 +123,7 @@ def callback(self, clusters, prefix): d = prefix[-1].dim # Do not waste time if definitely illegal - if any(SEQUENTIAL in c.properties[d] for c in clusters): + if any(c.properties.is_sequential(d) for c in clusters): return clusters # Do not waste time if definitely nothing to do @@ -136,17 +136,16 @@ def callback(self, clusters, prefix): return clusters processed = [] - for (it, guards), g in groupby(clusters, key=lambda c: self._key(c, prefix)): + for it, g in groupby(clusters, key=lambda c: self._key(c, prefix)): group = list(g) try: - test0 = any(SEQUENTIAL in c.properties[it.dim] for c in group) + test0 = any(c.properties.is_sequential(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)` + # `it` is None because `c`'s IterationSpace has no `d` Dimension test0 = True - if test0 or guards: + if test0: # Heuristic: no gain from fissioning if unable to ultimately # increase the number of collapsible iteration spaces, hence give up processed.extend(group) @@ -161,14 +160,10 @@ def callback(self, clusters, prefix): def _key(self, c, prefix): try: index = len(prefix) - dims = tuple(i.dim for i in prefix) - it = c.ispace[index] - guards = frozendict({d: v for d, v in c.guards.items() if d in dims}) - - return (it, guards) + return it except IndexError: - return (None, c.guards) + return None @timed_pass() From d0379ba84417eaf132d5cfcb0008465bc6608aa4 Mon Sep 17 00:00:00 2001 From: Fabio Luporini Date: Wed, 15 Jul 2026 14:15:33 +0100 Subject: [PATCH 2/3] compiler: Move expose_tuning_knobs to utils --- devito/passes/clusters/aliases.py | 22 +--------------------- devito/passes/clusters/utils.py | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/devito/passes/clusters/aliases.py b/devito/passes/clusters/aliases.py index ad40063a82..ec549d89e1 100644 --- a/devito/passes/clusters/aliases.py +++ b/devito/passes/clusters/aliases.py @@ -13,6 +13,7 @@ maximum, minimum, normalize_properties, relax_properties, unbounded, vmax, vmin ) from devito.passes.clusters.cse import _cse +from devito.passes.clusters.utils import expose_tuning_knobs from devito.symbolics import ( Uxmapper, estimate_cost, retrieve_functions, reuse_if_untouched, search, sympy_dtype, uxreplace @@ -1080,27 +1081,6 @@ def optimize_clusters_msds(clusters): return processed -def expose_tuning_knobs(clusters, sregistry): - """ - Replace all pre-existing BlockDimensions with fresh ones, to enable - separate tuning for the CIRE-generated temporaries. - """ - # Create the new BlockDimensions - callback = lambda i: sregistry.make_name(prefix=i) - - mapper = {} - for d in set().union(*[c.used_dimensions for c in clusters]): - if d.is_Block: - mapper.update(d._rebuild_hierarchy(callback)) - - if not mapper: - return clusters - - processed = [c.subs(mapper) for c in clusters] - - return processed - - def pick_best(variants): """ Return the variant with the best theoretical performance. diff --git a/devito/passes/clusters/utils.py b/devito/passes/clusters/utils.py index ff9cc2d95e..babf8689b5 100644 --- a/devito/passes/clusters/utils.py +++ b/devito/passes/clusters/utils.py @@ -2,7 +2,8 @@ from devito.tools import as_tuple from devito.types import CriticalRegion, Eq, Symbol -__all__ = ['in_critical_region', 'is_memcpy', 'make_critical_sequence'] +__all__ = ['expose_tuning_knobs', 'in_critical_region', 'is_memcpy', + 'make_critical_sequence'] def is_memcpy(expr): @@ -50,3 +51,24 @@ def in_critical_region(cluster, clusters): elif c.is_critical_region: maybe_found = c return None + + +def expose_tuning_knobs(clusters, sregistry): + """ + Replace all pre-existing BlockDimensions with fresh ones, to enable + separate tuning for the CIRE-generated temporaries. + """ + # Create the new BlockDimensions + callback = lambda i: sregistry.make_name(prefix=i) + + mapper = {} + for d in set().union(*[c.used_dimensions for c in clusters]): + if d.is_Block: + mapper.update(d._rebuild_hierarchy(callback)) + + if not mapper: + return clusters + + processed = [c.subs(mapper) for c in clusters] + + return processed From 0aa1c2a904fe7a5244d160f8a97ab696581e833f Mon Sep 17 00:00:00 2001 From: Fabio Luporini Date: Sat, 18 Jul 2026 14:13:05 +0100 Subject: [PATCH 3/3] compiler: Enhance ClusterGroup --- devito/ir/clusters/cluster.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/devito/ir/clusters/cluster.py b/devito/ir/clusters/cluster.py index 172567bb8e..e1c499d3cc 100644 --- a/devito/ir/clusters/cluster.py +++ b/devito/ir/clusters/cluster.py @@ -655,6 +655,12 @@ def __hash__(self): def concatenate(cls, *cgroups): return list(chain(*cgroups)) + def rebuild(self, **kwargs): + clusters = kwargs.get('clusters', self) + ispace = kwargs.get('ispace', self.ispace) + + return self.__class__(clusters, ispace=ispace) + @cached_property def exprs(self): return flatten(c.exprs for c in self) @@ -663,6 +669,10 @@ def exprs(self): def scope(self): return Scope(exprs=self.exprs) + @cached_property + def functions(self): + return self.scope.functions + @cached_property def ispace(self): return self._ispace