Skip to content

fix(arm64): make adm_dwt2_8_neon bit-exact with the scalar kernel - #1154

Merged
lusoris merged 1 commit into
masterfrom
fix/adm-dwt2-neon-parity
Aug 30, 2026
Merged

lusoris merged 1 commit into
masterfrom
fix/adm-dwt2-neon-parity

Conversation

@lusoris

@lusoris lusoris commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

ADR-1057 was a dropped filter tap in
adm_dwt2_8_neon that reached master and drifted the ARM Netflix golden. It
survived every test because no unit test covered adm_dwt2 on any
architecture
— test_integer_adm_simd.c reaches adm_cm, not adm_dwt2.

This adds that test. It immediately found two more divergences from the scalar
kernel.

1. Stale intermediate columns for widths ≡ 8 (mod 16)

integer_adm.c dispatches this kernel on !(w % 8):

if (flags & VMAF_ARM_CPU_FLAG_NEON) {
    if (!(w % 8))
        s->dwt2_8 = adm_dwt2_8_neon;

but its vertical pass advances 16 columns per iteration and stops at
w - 15, with no scalar tail:

for (int j = 0; j < w - 15; j += 16, ...)

For a width such as 584 or 776 the final 8 columns of tmplo / tmphi were
never written in that iteration, so the horizontal pass consumed whatever the
previous row had left in the shared buf->tmp_ref scratch.

2. Unmirrored final output column, at every width

The horizontal pass walks tmplo / tmphi with plain pointer arithmetic and
never consults ind_x, so for the last column it read tmplo[2j + 2] ==
tmplo[w] — one past the lo half, i.e. tmphi[0], since tmphi == tmplo + w —
where the scalar mirrors the index back to w - 1.

Score impact: none

I want to be precise about this rather than oversell it. I built a synthetic
584-wide clip specifically to trigger defect 1, and measured:

build VMAF
ARM NEON, pre-fix 80.322171
ARM NEON, post-fix 80.322171
x86 scalar 80.322171

ADM crops the affected border columns before they reach a feature value. And the
Netflix golden fixtures are 576, 1280 and 1920 wide — all multiples of 16 —
so defect 1 could never have surfaced there either.

This is a correctness and cross-backend-parity fix, not a scoring fix. It is
still worth making: defect 1 reads scratch entries that were never written in
that iteration, so the kernel's output depends on the previous row's residue.

Type

  • fix — bug fix
  • test — adds the missing coverage
  • simd — backend-specific

Checklist

  • Commits follow Conventional Commits.
  • make lint clean; clang-format and assertion-density pass on both touched files.
  • Unit tests pass: aarch64 98/98 under qemu-aarch64-static, x86 105/105.
  • SIMD path touched — bit-exactness against the scalar reference is exactly what the new test asserts, across six geometries. Worst divergence after the fix: 0.
  • No feature extractor added; the twin situation is unchanged.
  • New .c carries the license header.
  • Not a breaking change.
  • No ADR — bug fix, no architectural choice another engineer could reasonably have made differently.

Bug-status hygiene

  • docs/state.md updated — T-ADM-DWT2-NEON-PARITY-2026-08-30 under Recently closed.

Netflix golden-data gate

  • I did not modify any assertAlmostEqual(...) score. Verified score-neutral on the 576-wide golden pair (76.667831 pre- and post-fix) and on the synthetic 584-wide clip.

Deep-dive deliverables

  • Research digest — no digest needed: the investigation is the test itself, and its findings are recorded in docs/state.md and the commit message.
  • Decision matrix — no alternatives: only-one-way fix. A SIMD kernel either matches its scalar reference or does not.
  • AGENTS.md invariant note — captured in docs/rebase-notes.md instead: the invariant is about the relationship between the dispatch granularity (w % 8) and the vector width (16), which is not a package-scoped concern.
  • Reproducer / smoke-test command — below.
  • CHANGELOG fragment — changelog.d/fixed/adm-dwt2-neon-scalar-parity.md.
  • Rebase note — docs/rebase-notes.md, "fix/adm-dwt2-neon-parity".

Reproducer

meson setup build-arm64 core --cross-file build-aux/aarch64-linux-gnu.ini \
  -Denable_cuda=false -Denable_sycl=false -Denable_dnn=disabled
ninja -C build-arm64
meson test -C build-arm64 --suite=fast        # 98/98, incl. test_adm_dwt2_neon

Show the defects on the pre-fix kernel — revert adm_neon.c and the test reports
per-geometry mismatch counts:

16x16: 32 mismatches (32 last-column)     <- defect 2
24x16: 160 mismatches (32 last-column)    <- defect 2 + 128 stale columns (defect 1)
40x17: 180 mismatches (36 last-column)

128 = 4 columns × 8 rows × 4 subbands, exactly the region the missing vertical
tail leaves unwritten at w=24.

Known follow-ups

  • The same "no test covers this kernel" gap likely exists for other arm64/
    kernels. adm_cm has coverage via test_integer_adm_simd.c; the rest of
    adm_neon.c (decouple, csf, sum) does not.

ADR-1057 was a dropped filter tap in this kernel that reached master and
drifted the ARM Netflix golden. It survived every test because NO unit test
covered adm_dwt2 on any architecture -- the SIMD suite reaches adm_cm, not
adm_dwt2. This adds that test, and it immediately found two more divergences.

1. Stale intermediate columns for widths congruent to 8 mod 16.

   integer_adm.c dispatches this kernel on `!(w % 8)`, but its vertical pass
   advances 16 columns per iteration and stops at `w - 15`, with no scalar
   tail. For a width like 584 or 776 the final 8 columns of tmplo/tmphi were
   never written in that iteration, so the horizontal pass consumed whatever
   the previous row had left in the shared buf->tmp_ref scratch. Fixed by
   adding the tail.

2. Unmirrored final output column, at every width.

   The horizontal pass walks tmplo/tmphi with plain pointer arithmetic and
   never consults ind_x, so for the last column it read tmplo[2j + 2] ==
   tmplo[w]. That is one past the lo half -- the first element of tmphi, since
   tmphi == tmplo + w -- where the scalar mirrors the index back to w - 1.
   Fixed by recomputing that column with the indices dwt2_src_indices_filt()
   actually specifies.

NEITHER CHANGES A VMAF SCORE on anything tested. I built a synthetic 584-wide
clip specifically to trigger (1), and pre-fix, post-fix and the x86 scalar all
produce 80.322171: ADM crops the affected border columns before they reach a
feature value. The Netflix golden fixtures are 576, 1280 and 1920 wide -- all
multiples of 16 -- so (1) could never have surfaced there either. This is a
correctness and cross-backend-parity fix, not a scoring fix, and it is worth
making because (1) reads scratch entries that were never written in that
iteration: the output depends on the previous row's residue.

The new test asserts bit-exactness across six geometries covering w % 16 == 0,
w % 16 == 8 and odd heights. It reproduced both defects before the fix (24x16:
160 mismatches, 128 of them the stale columns) and reports 0 after.

Verified: aarch64 fast suite 98/98 under qemu-aarch64-static, x86 105/105,
clang-format and assertion-density clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lusoris
lusoris merged commit 89a8e32 into master Aug 30, 2026
27 of 61 checks passed
@lusoris
lusoris deleted the fix/adm-dwt2-neon-parity branch August 30, 2026 16:16
@lusoris lusoris added this to the 1.0.0 — First release milestone Sep 4, 2026
lusoris added a commit that referenced this pull request Sep 6, 2026
The ledger row for T-NEON-FMA-FLOAT-ADM-DWT2-2026-06-06 was
self-contradictory: a 2026-06-27 note inside the
T-MASTER-CI-TSAN-ARM-GOLDEN-2026-06-27 row said the bug "stays Open"
for a correct re-attempt, while its Recently-closed row already
recorded a 2026-08-30 closure — and that closure narrative described
only the integer-path dropped-tap defect and cited a branch name
(`fix/adr-1057-arm-fma-drift`) instead of a commit.

Re-verified against origin/master, with no defective code left to point
at:

- The float-ADM follow-up the row asked for landed in `a6c4dfffb`
  (PR #853): the kernel lives in a dedicated non-contracting TU
  `core/src/feature/arm64/float_adm_dwt2_neon.c`, built with
  `-ffp-contract=off` (`core/src/meson.build`), and
  `adm_dwt2_dispatch()` in `core/src/feature/adm.c` calls
  `float_adm_dwt2_neon()` under `VMAF_ARM_CPU_FLAG_NEON`. The scalar
  `adm_dwt2_s` carries the matching function-scoped guard, so both
  sides of the comparison are non-contracting and the 1-ULP FMA gap
  that motivated the row cannot arise.
- The integer `idx < 3` dropped filter tap in `adm_dwt2_8_neon` was
  fixed by `a013c1410` (PR #1134) and hardened to bit-exactness by
  `89a8e3258` (PR #1154); `6d61106ed` (PR #1156) added NEON parity
  tests for the remaining uncovered kernels.
- `core/test/test_float_adm_dwt2_neon.c` gates NEON-vs-scalar
  bit-exactness by bit pattern and is registered in the default `fast`
  suite.

The row stays in "Recently closed" (exactly one row for the id),
rewritten in past tense with real commit shas, and the stale "stays
Open" note is marked superseded so the next session does not
re-investigate. Documentation only — no code or behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lusoris added a commit that referenced this pull request Sep 6, 2026
The ledger row for T-NEON-FMA-FLOAT-ADM-DWT2-2026-06-06 was
self-contradictory: a 2026-06-27 note inside the
T-MASTER-CI-TSAN-ARM-GOLDEN-2026-06-27 row said the bug "stays Open"
for a correct re-attempt, while its Recently-closed row already
recorded a 2026-08-30 closure — and that closure narrative described
only the integer-path dropped-tap defect and cited a branch name
(`fix/adr-1057-arm-fma-drift`) instead of a commit.

Re-verified against origin/master, with no defective code left to point
at:

- The float-ADM follow-up the row asked for landed in `a6c4dfffb`
  (PR #853): the kernel lives in a dedicated non-contracting TU
  `core/src/feature/arm64/float_adm_dwt2_neon.c`, built with
  `-ffp-contract=off` (`core/src/meson.build`), and
  `adm_dwt2_dispatch()` in `core/src/feature/adm.c` calls
  `float_adm_dwt2_neon()` under `VMAF_ARM_CPU_FLAG_NEON`. The scalar
  `adm_dwt2_s` carries the matching function-scoped guard, so both
  sides of the comparison are non-contracting and the 1-ULP FMA gap
  that motivated the row cannot arise.
- The integer `idx < 3` dropped filter tap in `adm_dwt2_8_neon` was
  fixed by `a013c1410` (PR #1134) and hardened to bit-exactness by
  `89a8e3258` (PR #1154); `6d61106ed` (PR #1156) added NEON parity
  tests for the remaining uncovered kernels.
- `core/test/test_float_adm_dwt2_neon.c` gates NEON-vs-scalar
  bit-exactness by bit pattern and is registered in the default `fast`
  suite.

The row stays in "Recently closed" (exactly one row for the id),
rewritten in past tense with real commit shas, and the stale "stays
Open" note is marked superseded so the next session does not
re-investigate. Documentation only — no code or behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lusoris added a commit that referenced this pull request Sep 6, 2026
The ledger row for T-NEON-FMA-FLOAT-ADM-DWT2-2026-06-06 was
self-contradictory: a 2026-06-27 note inside the
T-MASTER-CI-TSAN-ARM-GOLDEN-2026-06-27 row said the bug "stays Open"
for a correct re-attempt, while its Recently-closed row already
recorded a 2026-08-30 closure — and that closure narrative described
only the integer-path dropped-tap defect and cited a branch name
(`fix/adr-1057-arm-fma-drift`) instead of a commit.

Re-verified against origin/master, with no defective code left to point
at:

- The float-ADM follow-up the row asked for landed in `a6c4dfffb`
  (PR #853): the kernel lives in a dedicated non-contracting TU
  `core/src/feature/arm64/float_adm_dwt2_neon.c`, built with
  `-ffp-contract=off` (`core/src/meson.build`), and
  `adm_dwt2_dispatch()` in `core/src/feature/adm.c` calls
  `float_adm_dwt2_neon()` under `VMAF_ARM_CPU_FLAG_NEON`. The scalar
  `adm_dwt2_s` carries the matching function-scoped guard, so both
  sides of the comparison are non-contracting and the 1-ULP FMA gap
  that motivated the row cannot arise.
- The integer `idx < 3` dropped filter tap in `adm_dwt2_8_neon` was
  fixed by `a013c1410` (PR #1134) and hardened to bit-exactness by
  `89a8e3258` (PR #1154); `6d61106ed` (PR #1156) added NEON parity
  tests for the remaining uncovered kernels.
- `core/test/test_float_adm_dwt2_neon.c` gates NEON-vs-scalar
  bit-exactness by bit pattern and is registered in the default `fast`
  suite.

The row stays in "Recently closed" (exactly one row for the id),
rewritten in past tense with real commit shas, and the stale "stays
Open" note is marked superseded so the next session does not
re-investigate. Documentation only — no code or behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lusoris added a commit that referenced this pull request Sep 7, 2026
The ledger row for T-NEON-FMA-FLOAT-ADM-DWT2-2026-06-06 was
self-contradictory: a 2026-06-27 note inside the
T-MASTER-CI-TSAN-ARM-GOLDEN-2026-06-27 row said the bug "stays Open"
for a correct re-attempt, while its Recently-closed row already
recorded a 2026-08-30 closure — and that closure narrative described
only the integer-path dropped-tap defect and cited a branch name
(`fix/adr-1057-arm-fma-drift`) instead of a commit.

Re-verified against origin/master, with no defective code left to point
at:

- The float-ADM follow-up the row asked for landed in `a6c4dfffb`
  (PR #853): the kernel lives in a dedicated non-contracting TU
  `core/src/feature/arm64/float_adm_dwt2_neon.c`, built with
  `-ffp-contract=off` (`core/src/meson.build`), and
  `adm_dwt2_dispatch()` in `core/src/feature/adm.c` calls
  `float_adm_dwt2_neon()` under `VMAF_ARM_CPU_FLAG_NEON`. The scalar
  `adm_dwt2_s` carries the matching function-scoped guard, so both
  sides of the comparison are non-contracting and the 1-ULP FMA gap
  that motivated the row cannot arise.
- The integer `idx < 3` dropped filter tap in `adm_dwt2_8_neon` was
  fixed by `a013c1410` (PR #1134) and hardened to bit-exactness by
  `89a8e3258` (PR #1154); `6d61106ed` (PR #1156) added NEON parity
  tests for the remaining uncovered kernels.
- `core/test/test_float_adm_dwt2_neon.c` gates NEON-vs-scalar
  bit-exactness by bit pattern and is registered in the default `fast`
  suite.

The row stays in "Recently closed" (exactly one row for the id),
rewritten in past tense with real commit shas, and the stale "stays
Open" note is marked superseded so the next session does not
re-investigate. Documentation only — no code or behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lusoris added a commit that referenced this pull request Sep 7, 2026
…#1331)

The ledger row for T-NEON-FMA-FLOAT-ADM-DWT2-2026-06-06 was
self-contradictory: a 2026-06-27 note inside the
T-MASTER-CI-TSAN-ARM-GOLDEN-2026-06-27 row said the bug "stays Open"
for a correct re-attempt, while its Recently-closed row already
recorded a 2026-08-30 closure — and that closure narrative described
only the integer-path dropped-tap defect and cited a branch name
(`fix/adr-1057-arm-fma-drift`) instead of a commit.

Re-verified against origin/master, with no defective code left to point
at:

- The float-ADM follow-up the row asked for landed in `a6c4dfffb`
  (PR #853): the kernel lives in a dedicated non-contracting TU
  `core/src/feature/arm64/float_adm_dwt2_neon.c`, built with
  `-ffp-contract=off` (`core/src/meson.build`), and
  `adm_dwt2_dispatch()` in `core/src/feature/adm.c` calls
  `float_adm_dwt2_neon()` under `VMAF_ARM_CPU_FLAG_NEON`. The scalar
  `adm_dwt2_s` carries the matching function-scoped guard, so both
  sides of the comparison are non-contracting and the 1-ULP FMA gap
  that motivated the row cannot arise.
- The integer `idx < 3` dropped filter tap in `adm_dwt2_8_neon` was
  fixed by `a013c1410` (PR #1134) and hardened to bit-exactness by
  `89a8e3258` (PR #1154); `6d61106ed` (PR #1156) added NEON parity
  tests for the remaining uncovered kernels.
- `core/test/test_float_adm_dwt2_neon.c` gates NEON-vs-scalar
  bit-exactness by bit pattern and is registered in the default `fast`
  suite.

The row stays in "Recently closed" (exactly one row for the id),
rewritten in past tense with real commit shas, and the stale "stays
Open" note is marked superseded so the next session does not
re-investigate. Documentation only — no code or behaviour change.

Co-authored-by: Lusoris <lusoris@pm.me>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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