-
Notifications
You must be signed in to change notification settings - Fork 257
compiler: compute sparse position/floor in fp64 to fix off-by-one cell shift #2992
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,8 +15,8 @@ | |
| 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 | ||
| INT, Uxmapper, estimate_cost, retrieve_functions, reuse_if_untouched, search, | ||
| sympy_dtype, uxreplace | ||
| ) | ||
| from devito.tools import ( | ||
| Reconstructable, Stamp, as_mapper, as_tuple, flatten, frozendict, generator, | ||
|
|
@@ -295,6 +295,10 @@ def _do_generate(self, exprs, exclude, cbk_search, cbk_compose=None): | |
|
|
||
| class CireInvariants(CireTransformerLegacy, Queue): | ||
|
|
||
| # Predicate on Cluster used to pick which ones this pass fires on. | ||
| # Subclasses override to target a different kind of cluster. | ||
| _cluster_filter = staticmethod(lambda c: c.is_dense) | ||
|
|
||
| def __init__(self, sregistry, options, platform): | ||
| super().__init__(sregistry, options, platform) | ||
|
|
||
|
|
@@ -324,7 +328,8 @@ def callback(self, clusters, prefix, xtracted=None): | |
| key = lambda c: self._lookup_key(c, d) | ||
| processed = list(clusters) | ||
| for ak, group in as_mapper(clusters, key=key).items(): | ||
| g = [c for c in group if c.is_dense and c not in xtracted] | ||
| g = [c for c in group | ||
| if self._cluster_filter(c) and c not in xtracted] | ||
| if not g: | ||
| continue | ||
|
|
||
|
|
@@ -387,6 +392,52 @@ def _generate(self, cgroup, exclude): | |
| yield self._do_generate(exprs, exclude, cbk_search) | ||
|
|
||
|
|
||
| def _is_floor(e): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is quite hacky, let the |
||
| return getattr(e, 'is_Function', False) and e.func.__name__ == 'floor' | ||
|
|
||
|
|
||
| class CireInvariantsFloor(CireInvariants): | ||
|
|
||
| """ | ||
| Hoist `INT(floor(x))` expressions -- typically the integer cell of a | ||
| sparse position `INT(floor((c - o)/h))` -- into an int32 preamble Array. | ||
| `CireInvariantsElementary`'s commutativity gate rejects both `floor(...)` | ||
| (Cast in the argument makes `is_commutative == False`) and | ||
| `INT(floor(...))` (a `Cast`, `is_commutative is None`), so we handle | ||
| them here. Fires on every cluster: hoisting an invariant integer floor | ||
| out of an inner loop is a strict win regardless of the cluster kind. | ||
| """ | ||
|
|
||
| _cluster_filter = staticmethod(lambda c: True) | ||
|
|
||
| def _generate(self, cgroup, exclude): | ||
| counter = generator() | ||
| make_i32 = lambda: Symbol(name=f'dummy{counter()}', dtype=np.int32) | ||
|
|
||
| mapper = Uxmapper() | ||
| for e in cgroup.exprs: | ||
| for f in search(e, _is_floor, 'all', 'bfs'): | ||
| cand = INT(f) | ||
| if not {a.function for a in cand.free_symbols} & exclude: | ||
| mapper.add(cand, make_i32, None) | ||
|
|
||
| yield mapper | ||
|
|
||
| def _choose(self, aliases, cgroup, mapper): | ||
| # Skip score-based filtering: hoisting a floor out of an inner | ||
| # loop is a strict flops win regardless of working-set size. | ||
| exprs = cgroup.exprs | ||
|
|
||
| aliases = AliasList(aliases) | ||
| if not aliases: | ||
| return exprs, aliases | ||
|
|
||
| subs = {k: v for k, v in mapper.items() | ||
| if v.free_symbols & set(aliases.aliaseds)} | ||
| exprs = [uxreplace(e, subs) for e in exprs] | ||
| return exprs, aliases | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. blank line |
||
|
|
||
|
|
||
| class CireDerivatives(CireTransformerLegacy): | ||
|
|
||
| def __init__(self, sregistry, options, platform): | ||
|
|
@@ -519,7 +570,8 @@ def _cbk_search2(self, expr, rank): | |
| # Subpass mapper | ||
| modes = { | ||
| 'invariants': [CireInvariantsElementary, | ||
| CireInvariantsDivs], | ||
| CireInvariantsDivs, | ||
| CireInvariantsFloor], | ||
| 'eval-derivs': [CireEvalDerivatives], # NOTE: legacy pass | ||
| 'index-derivs': [CireIndexDerivatives], | ||
| } | ||
|
|
@@ -707,8 +759,14 @@ def lower_aliases(aliases, meta, opt_maxpar, opt_block_temps): | |
| # not as an Indexed index. Then, it needs to be added to | ||
| # the `writeto` region too | ||
| interval = i | ||
| elif writeto: | ||
| # `d` is inner to the writeto region and unused by the | ||
| # alias -- skip it, otherwise the preamble would iterate | ||
| # over it and store the same value repeatedly. | ||
| continue | ||
| else: | ||
| # E.g., `x0_blk0` or (`a[y_m+1]` => `y not in imapper`) | ||
| # E.g., `x0_blk0` (outer to writeto, must stay in ispace | ||
| # so later passes -- `Lift`, `Fuse` -- see it) | ||
| intervals[d] = i | ||
| continue | ||
|
|
||
|
|
@@ -1565,10 +1623,10 @@ def make_rotations_table(d, v): | |
|
|
||
| def cit(ispace0, ispace1): | ||
| """ | ||
| The Common IterationIntervals of two IterationSpaces. | ||
| The Common IterationIntervals of two IterationSpaces (the shared prefix). | ||
| """ | ||
| found = [] | ||
| for it0, it1 in zip(ispace0.itintervals, ispace1.itintervals, strict=True): | ||
| for it0, it1 in zip(ispace0.itintervals, ispace1.itintervals, strict=False): | ||
| if it0 == it1: | ||
| found.append(it0) | ||
| else: | ||
|
|
||
Large diffs are not rendered by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why don't we always do it with all
floors (and maybe not just that), be it dense or sparse ?