Conversation
Lowering emitted the *Python variable name* an offset was bound to as the IR
shift tag, because `ts.OffsetType` did not carry the tag. Embedded execution
keys on `FieldOffset.value`, so the same program needed a different offset
provider depending on how it was run:
MyOff = FieldOffset("TAGNAME", ...)
embedded: {"TAGNAME": conn} OK ; {"MyOff": conn} -> KeyError 'TAGNAME'
compiled: {"MyOff": conn} OK ; {"TAGNAME": conn} -> KeyError 'MyOff'
`ts.OffsetType` now carries `tag`. It is `Optional`, not required: a Cartesian
shift built from `Dim + offset` has no tag and needs none, since it lowers to a
`CartesianOffset` carrying both dimensions with no provider lookup. Subscripting
(`Off[1]`) drops the local dimension but propagates the tag, which is the
offset's identity.
The regression test grows from one cell -- `a(Off[1])` on gtfn -- to the cross
product of {shift, neighbor_sum} x {tag != variable name, tag != local dimension
name} over the whole backend matrix. Each `Case` holds exactly one connectivity
on purpose: DaCe walks every offset-provider entry while building the SDFG and
looks a connectivity up by its *local dimension's* name, so a second,
non-conforming entry fails a program that does not use it.
The cells that still fail are marked, per backend, from measurement:
* `uses_offset_tag_differing_from_local_dim` -- DaCe only; the gtfn shift path
was fixed in GridTools#1789.
* `uses_offset_tag_differing_from_local_dim_in_reduction` -- embedded, gtfn,
DaCe and the lower-level `iterator/embedded.py` execution. Notably *not* the
roundtrip backend, which passes; only `roundtrip.gtir` fails.
Both remaining constraints are the same one: those paths resolve a connectivity
through the local dimension's name rather than the offset's identity. Fixing
that needs a back-pointer from the local dimension to its connectivity, which is
a separate change.
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lowering emitted the Python variable name an offset was bound to as the IR shift tag, because
ts.OffsetTypedid not carry the tag. Embedded execution keys onFieldOffset.value, so the same program needed a different offset provider depending on how it was run — confirmed by running it on v1.2.2:ts.OffsetTypenow carriestag, and lowering emits it.Why
tagisOptionalA Cartesian shift written
Dim + offsethas no tag and needs none — it lowers to anitir.CartesianOffsetcarrying both dimensions, with no provider lookup.type_deductionbuilds anOffsetTypefor exactly that case (:711), so a required field would break it. Subscripting (Off[1]) drops the local dimension but propagates the tag, which is the offset's identity.For a declaration whose tag differs from the variable it is bound to, compiled backends previously required
offset_provider={"MyOff": conn}and now require{"TAGNAME": conn}. That divergence from embedded execution is the bug being fixed, but it is user-visible.ICON4Py is unaffected: all 16
FieldOffsetdeclarations have tag == variable name, there are noKoff[...]subscripts in model code, andas_offsetnever consults the tag.No
CHANGELOG.mdentry — that file is only ever touched by release PRs.Tests
The regression test grows from one cell (
a(Off[1])onGTFN_CPU) to{shift, neighbor_sum} × {tag ≠ variable name, tag ≠ local dimension name}across the whole backend matrix, plus two lowering unit tests intest_foast_to_gtir.pythat assert the emittedOffsetLiteraldirectly. Both unit tests were verified to fail with the fix reverted.Each
Caseholds exactly one connectivity on purpose: DaCe walks every offset-provider entry while building the SDFG and looks a connectivity up by its local dimension's name, so a second non-conforming entry fails a program that never uses it.The remaining failures are marked per backend, from measurement rather than assumption:
Note
roundtrippasses the reduction case whileroundtrip.gtirdoes not:roundtrip.defaultrunsapply_common_transforms, so the reduction unrolls keyed by the offset tag, whereasroundtrip.gtirruns only the fieldview transforms and reachesiterator/embedded.pykeyed on the local dimension.Both remaining constraints are one underlying issue: those paths resolve a connectivity through the local dimension's name rather than the offset's identity. Fixing it needs a back-pointer from the local dimension to its connectivity, which is a later step in this stack.
GPU and JAX cells are marked by shared-code-path reasoning, not measurement — they skip locally.
xfail_strictis on, so if any is wrong CI fails loudly rather than passing silently.Verification
nox-equivalent local runs:pytest tests/next_tests -m "not uses_dace"→ 4477 passed / 0 failed;-m uses_dace→ 1477 passed / 0 failed;mypy src/clean;tach checkclean;pre-commit runclean.Context
First PR of a stack implementing
egparedes/connectivities-as-types, an alternative to #2844. This PR stands alone — it is a bugfix that is correct regardless of whether the rest of the stack lands.