Repository navigation
Conversation
lusoris
force-pushed
the
port/upstream-2026-09
branch
from
September 19, 2026 21:04
5ad4972 to
a44c65c
Compare
lusoris
force-pushed
the
fix/adm-dwt2-16bit-overflow
branch
from
September 19, 2026 21:29
675f178 to
f71e570
Compare
Scale 0's vertical DWT pass sums filter[k] * s[k] before normalising. The first three low-pass taps add up to 50582, so at 16 bpc that int32 partial sum overflows once three consecutive samples reach 42456: undefined behaviour in the scalar adm_dwt2_vpass_16() and in the scalar vertical loops of adm_dwt2_16_avx2() and adm_dwt2_16_avx512(). Upstream has the same code. A UBSan build reports three sites per kernel on bright 16-bit frames. Scores were right because the normalised value fits in int32 and two's-complement wrap-around undoes itself, which is also why no parity test saw it. The new adm_dwt2_vpass16_tap4() in integer_adm.h forms the response in int64; the three kernels share it. 10, 12 and 16 bpc on scalar, AVX2 and AVX-512 are identical at %.17g before and after. test_integer_adm_dwt16_range scores bright 16-bit noise on every dispatch level and requires SIMD to equal scalar bit for bit; under UBSan it reaches all nine sites without the fix. The GPU twins carry the same int32 sum and are tracked as T-GPU-ADM-DWT2-16BIT-INT32-OVERFLOW-2026-09-18.
The open GPU row and the research note listed SYCL among the twins with the int32 overflow. Its vertical pass (integer_adm_sycl.cpp) accumulates every tap and the normalisation in int64 already; only CUDA, HIP and Metal are affected.
lusoris
force-pushed
the
fix/adm-dwt2-16bit-overflow
branch
from
September 19, 2026 21:58
f71e570 to
3c336ec
Compare
12 tasks done
Contributor
Author
|
Absorbed into the ADM stack train #1507, per your direction to fold this stack the way #1506 was folded. This PR targeted the one below it in a five-deep stack, so none of the five could merge until every one below had merged and been restacked — five sequential rebase-plus-CI rounds. #1507 is one. Your work is in it unchanged; that PR's description lists the six defects the fold itself surfaced, none of which an individual PR could see, because each gate only looks at the files its own PR touches. The branch stays on the remote. |
lusoris
added a commit
that referenced
this pull request
Sep 22, 2026
…ny frames, HIP buffer by pointer (#1507) Integration train for the five-deep ADM/GPU stack behind #1473, folded into one merge per maintainer direction. Each PR previously targeted the one below it, so none could merge until every one below had. - #1474 AVX2 / AVX-512 contrast masking wraps like scalar on full-range noise - #1477 CPU 16-bit vertical DWT sum formed in int64 — int32 overflows at 16 bpc once three samples reach 42456 - #1476 Integer-ADM twins agree with the CPU on tiny frames; SYCL wrap and rounding fixes; GPU tidy-lane repairs - #1478 The same 16-bit scale-0 vertical DWT fix in the CUDA, HIP and Metal twins - #1481 HIP ADM kernels take `AdmBufferHip` by pointer (ADR-0759) rather than copying 328 bytes of arguments per launch Required Checks Aggregator green on 9bae48c with no failing check; branch level with master at 371ff58. Merged with admin bypass because the repository has a single collaborator who cannot self-approve (ADR-1252). Unblocks #1518, which depends on the SIMD contrast-masking fix — see T-CUDA-ADM-SMALL-BORDER-PARITY-2026-09-21 in docs/state.md.
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.
Summary
Integer ADM's 16-bit vertical DWT pass summed four weighted samples in
int32_t. That overflows on bright 16-bit input, which is undefined behaviour, in the scalar path and in both x86 kernels. The sum is now formed in 64 bits. No score changes. Stacked on #1473, parallel to #1474 and #1476; review #1473 first.The defect. Scale 0 forms
sum(filter[k] * s[k])and only then subtracts46342 * 2^(bpc - 1). The first three low-pass taps (15826, 27411, 7345) add up to 50582, so at 16 bpc the partial sum passesINT32_MAXonce three consecutive samples reach 42456. The same int32 sum sits in three places:adm_dwt2_vpass_16();adm_dwt2_16_avx2();adm_dwt2_16_avx512().Upstream Netflix/vmaf has the same code.
Why nothing noticed. The normalised value is at most
54822 * 32768in magnitude, inside int32, so two's-complement wrap-around undoes the overflow and every path gets the right answer on the hardware we test. Parity tests cannot see it; only a sanitizer build can.The fix. A new
adm_dwt2_vpass16_tap4()ininteger_adm.hforms the response in int64, as the file'si4_dwt2_tap4()already does for scales 1–3. All three kernels share it. For in-range input the result equals the old wrapped one. The 8-bit pass is unchanged: 255 × 50582 fits in int32.Regression test.
test_integer_adm_dwt16_rangescores bright 16-bit noise at two sizes on every dispatch level and requires SIMD to equal scalar bit for bit. The sanitizer lane (halt_on_error=1) is what gives it teeth: under UBSan it reaches all nine overflow sites without the fix, three per kernel, and none with it.no docs needed: bug fix with no user-visible change; every score is byte-identical before and after, and no option, output or supported input changes.
Type
feat— new featurefix— bug fixperf— performance improvementrefactor— no behavior changedocs— documentation onlytest— test-onlybuild/ci— tooling / infraport— cherry-pick from upstream Netflix/vmafsycl/cuda/simd— backend-specificChecklist
make format && make lintis green locally: pre-commit on every changed file passes, and clang-tidy (CPU lane) and cppcheck report 0 findings on the four touched TUs.meson test -C build: fast suite 139/139./cross-backend-diffand the worst ULP is ≤ 2: 0 ULP. Scalar, AVX2 and AVX-512 are bit-identical at%.17gbefore and after, and to each other..c/.cpp/.cu/.h/.hpp, it has the appropriate license header (seeCONTRIBUTING.md).!orBREAKING CHANGE:and the migration path is documented below: not breaking.docs/adr/_index_fragments/<NNNN-slug>.mdand the slug is appended todocs/adr/_index_fragments/_order.txt: no ADR, bug fix.Bug-status hygiene (ADR-0165)
docs/state.md:T-ADM-DWT2-16BIT-INT32-OVERFLOW-2026-09-18closed.T-GPU-ADM-DWT2-16BIT-INT32-OVERFLOW-2026-09-18opened for the GPU twins.Netflix golden-data gate (ADR-0024)
assertAlmostEqual(...)score in the Netflix golden Python tests.Deep-dive deliverables (ADR-0108)
docs/research/2063-upstream-sync-2026-09-adm-vif-simd.md, new section "Int32 overflow in the 16-bit vertical DWT pass".uint32_t, are tabulated in the digest section).core/src/feature/AGENTS.md, "Integer ADM's 16-bit vertical DWT sums in int64".changelog.d/fixed/adm-dwt2-16bit-overflow.md.docs/rebase-notes.md: keepadm_dwt2_vpass16_tap4()when a sync touches the 16-bit vertical loops.Reproducer
Verified locally
test_integer_adm_dwt16_range, UBSan, old codeinteger_adm.c1463/1464/1513,adm_avx2.c3392/3393/3397,adm_avx512.c3495/3496/3500)--precision maxscripts/dev/preflight.shcheck_exported_symbolsflags ASan's__start_asan_globalsunder GNU ld, and m32 sweeps thex86/andarm64/files the i686 lane never buildsKnown follow-ups
adm_dwt2.cu), HIP (adm_dwt2.hip) and Metal (integer_adm.metal) twins sum the same response in int32 (T-GPU-ADM-DWT2-16BIT-INT32-OVERFLOW-2026-09-18); the SYCL twin already forms it in int64. Their fix will be a PR stacked on fix(gpu): make the integer ADM twins agree with the CPU on tiny frames and full-range content #1476.