Skip to content

fix[next-dace]: detect write-after-read hazard in copy chain removal - #2863

Open
edopao wants to merge 1 commit into
GridTools:mainfrom
edopao:fix/copy-chain-remover-war
Open

fix[next-dace]: detect write-after-read hazard in copy chain removal#2863
edopao wants to merge 1 commit into
GridTools:mainfrom
edopao:fix/copy-chain-remover-war

Conversation

@edopao

@edopao edopao commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Description

CopyChainRemover merges a (A1) -> (A2) copy by removing one container and
rewiring the writes onto the survivor. In PULL mode a transient double buffer
A1 is removed and its writes are taken over by A2, which moves those writes
back to where A1 was produced.

When the surviving container is a global that is also read elsewhere in the
same state, the removed transient was acting as a double buffer: it held the new
value while the old one was still being read. Merging it away leaves the write no
longer ordered after those reads, so the readers could observe the new value —
silently wrong results.

This is the pattern generated by an in-place update stencil, i.e. a field that a
field_operator call takes as an input and also produces as an output.

Fix

Add _creates_write_after_read_hazard: when the surviving container is a
non-transient (global) that another AccessNode of the state still reads
(out_degree != 0), reject the transformation. Transients are written only once
(ADR-18), so they are unaffected and are skipped by the check.

Tests

test_copy_chain_destination_read_in_map_no_apply in test_copy_chain_remover.py
reproduces the in-place update pattern:

for i in range(10):
    d[i] = c[i] + 1.0  # `c` read in a branch independent of the producer of `b`.
    b[i] = a[i] * 2.0
c[:] = b[:]  # Copy chain `(b) -> (c)`: the surviving global `c` is read in the Map.

The (b) -> (c) copy chain must not be removed, since c survives and is still
read in the Map. The test compiles and runs the SDFG before and after, asserts the
transformation does not apply, and that the transient double buffer b is
retained. Verified that neutralizing the new guard makes the transformation apply,
confirming the test reproduces the issue.

Notes

This is one of a family of write-after-read fixes for in-place update stencils on
the DaCe backend (cf. #2815 GT4PyMapBufferElimination, #2816 DoubleWriteRemover,
#2817 GT4PyStateFusion). It targets a distinct transformation (CopyChainRemover)
and does not overlap with those PRs; the reproducer deliberately mirrors the SDFG
shape used in #2816. The fix was extracted from the dace_refactor_lowering draft
(#2690) into this standalone PR.

@edopao
edopao force-pushed the fix/copy-chain-remover-war branch from 1e3e29c to eca19e5 Compare September 4, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant