PR #24374 opened by zuxy URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24374 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24374.patch
Many architectures mishandle edge cases in weight and/or bi-weight calculation, either do not saturate properly or apply saturation in a wrong order. This series grant them parity with x86. neon weight: add/sub->sqadd/sqsub neon bi-weight: multiply-accumulate wraps instead of saturates; fix: do not accumulate to offset, but saturate with offset after dot product riscv bi-weight: likewise loonarch bi-weight: likewise ppc bi-weight: first product saturates with offset before adding the other product leading to wrong result; fix: dot product first, saturate with offset later mmi bi-weight: likewise >From 5d8036f3fbbb03057fa62c1ce65d90346c0baa79 Mon Sep 17 00:00:00 2001 From: Zuxy Meng <[email protected]> Date: Fri, 4 Sep 2026 21:09:51 -0700 Subject: [PATCH 1/6] avcodec/arm|aarch64/h264dsp: Fix edge cases for weight Add/sub with saturation is used only on log2_denom > 1 path, but with log2_denom == 1 (block[x]*weight + offset << 1) can fall below S16_MIN. Use saturation in all paths for safety. This fixes the weight checkasm test for arm and aarch64 Signed-off-by: Zuxy Meng <[email protected]> --- libavcodec/aarch64/h264dsp_neon.S | 4 ++-- libavcodec/arm/h264dsp_neon.S | 4 ++-- tests/checkasm/h264dsp.c | 7 ------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/libavcodec/aarch64/h264dsp_neon.S b/libavcodec/aarch64/h264dsp_neon.S index 723b692019..c09db164b6 100644 --- a/libavcodec/aarch64/h264dsp_neon.S +++ b/libavcodec/aarch64/h264dsp_neon.S @@ -810,9 +810,9 @@ function ff_weight_h264_pixels_\w\()_neon, export=1 dup v18.8h, w6 cmp w4, #0 b.lt 10f - weight_\w add + weight_\w sqadd 10: neg w4, w4 - weight_\w sub + weight_\w sqsub endfunc .endm diff --git a/libavcodec/arm/h264dsp_neon.S b/libavcodec/arm/h264dsp_neon.S index 5fed6848d8..975b61c8c0 100644 --- a/libavcodec/arm/h264dsp_neon.S +++ b/libavcodec/arm/h264dsp_neon.S @@ -549,9 +549,9 @@ function ff_weight_h264_pixels_\w\()_neon, export=1 vdup.16 q9, lr cmp r12, #0 blt 10f - weight_\w vadd.s16 + weight_\w vqadd.s16 10: rsb r12, r12, #0 - weight_\w vsub.s16 + weight_\w vqsub.s16 endfunc .endm diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 30478f2956..a38ee32d9c 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -500,10 +500,6 @@ static void check_loop_filter_intra(void) } } -// neon fails at edge cases -#define H264_CHECK_WEIGHT (!ARCH_ARM && !ARCH_AARCH64) - -#if H264_CHECK_WEIGHT static void check_weight(void) { LOCAL_ALIGNED_16(uint8_t, dst, [32 * 32 * 2]); @@ -547,7 +543,6 @@ static void check_weight(void) } } } -#endif // only arch that can pass test #define H264_CHECK_BIWEIGHT ARCH_X86 @@ -634,10 +629,8 @@ void checkasm_check_h264dsp(void) check_loop_filter_intra(); report("loop_filter_intra"); -#if H264_CHECK_WEIGHT check_weight(); report("weight"); -#endif #if H264_CHECK_BIWEIGHT check_biweight(); -- 2.52.0 >From 6ecc21d985078a1b2a20f3f4f83fd359e4522f78 Mon Sep 17 00:00:00 2001 From: Zuxy Meng <[email protected]> Date: Fri, 4 Sep 2026 21:18:41 -0700 Subject: [PATCH 2/6] avcodec/ppc/h264dsp: Fix edge cases for bi-weight on ppc S16 saturating sum must be computed dot-product-first. The Altivec code added the offset to the first product before adding the second product, so an intermediate saturation could corrupt the result even when the true sum fits. Swap the two vec_adds to form the dot product first. This fixes bi-weight checkasm test for PPC. Signed-off-by: Zuxy Meng <[email protected]> --- libavcodec/ppc/h264dsp.c | 4 ++-- tests/checkasm/h264dsp.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libavcodec/ppc/h264dsp.c b/libavcodec/ppc/h264dsp.c index d832e7f01c..c558dafa0b 100644 --- a/libavcodec/ppc/h264dsp.c +++ b/libavcodec/ppc/h264dsp.c @@ -749,16 +749,16 @@ void biweight_h264_W_altivec(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int h v0 = vec_mladd(v0, vweightd, zero_s16v); v2 = vec_mladd(v2, vweights, zero_s16v); - v0 = vec_adds(v0, voffset); v0 = vec_adds(v0, v2); + v0 = vec_adds(v0, voffset); v0 = vec_sra(v0, vlog2_denom); } if (w == 16 || !dst_aligned) { v1 = vec_mladd(v1, vweightd, zero_s16v); v3 = vec_mladd(v3, vweights, zero_s16v); - v1 = vec_adds(v1, voffset); v1 = vec_adds(v1, v3); + v1 = vec_adds(v1, voffset); v1 = vec_sra(v1, vlog2_denom); } vdst = vec_packsu(v0, v1); diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index a38ee32d9c..61839b13d6 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -544,8 +544,8 @@ static void check_weight(void) } } -// only arch that can pass test -#define H264_CHECK_BIWEIGHT ARCH_X86 +// only archs that can pass test +#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC) #if H264_CHECK_BIWEIGHT static void check_biweight(void) -- 2.52.0 >From e9fb700ac5edece7bbbd6aad6cbc8ffdcd8fab4c Mon Sep 17 00:00:00 2001 From: Zuxy Meng <[email protected]> Date: Fri, 4 Sep 2026 21:21:45 -0700 Subject: [PATCH 3/6] avcodec/mips/h264dsp_mmi: Fix edge cases for bi-weight on MMI S16 saturating sum must be computed dot-product-first. The MMI code added the offset to the first product before adding the second product. Swap the paddsh pairs in biweight_pixels16/8/4_8_mmi to form the dot product first. This fixes bi-weight checkasm test for MIPS as MSA already handles these cases. Signed-off-by: Zuxy Meng <[email protected]> --- libavcodec/mips/h264dsp_mmi.c | 14 +++++++------- tests/checkasm/h264dsp.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libavcodec/mips/h264dsp_mmi.c b/libavcodec/mips/h264dsp_mmi.c index bee4e84e37..c42a5ad98b 100644 --- a/libavcodec/mips/h264dsp_mmi.c +++ b/libavcodec/mips/h264dsp_mmi.c @@ -1170,10 +1170,10 @@ void ff_h264_biweight_pixels16_8_mmi(uint8_t *dst, uint8_t *src, "pmullh %[ftmp8], %[ftmp8], %[ftmp4] \n\t" "pmullh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" "pmullh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "paddsh %[ftmp7], %[ftmp7], %[ftmp5] \n\t" - "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "paddsh %[ftmp7], %[ftmp7], %[ftmp8] \n\t" "paddsh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "paddsh %[ftmp7], %[ftmp7], %[ftmp5] \n\t" + "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "psrah %[ftmp7], %[ftmp7], %[ftmp6] \n\t" "psrah %[ftmp1], %[ftmp1], %[ftmp6] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp7] \n\t" @@ -1188,10 +1188,10 @@ void ff_h264_biweight_pixels16_8_mmi(uint8_t *dst, uint8_t *src, "pmullh %[ftmp8], %[ftmp8], %[ftmp4] \n\t" "pmullh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" "pmullh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "paddsh %[ftmp7], %[ftmp7], %[ftmp5] \n\t" - "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "paddsh %[ftmp7], %[ftmp7], %[ftmp8] \n\t" "paddsh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "paddsh %[ftmp7], %[ftmp7], %[ftmp5] \n\t" + "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "psrah %[ftmp7], %[ftmp7], %[ftmp6] \n\t" "psrah %[ftmp1], %[ftmp1], %[ftmp6] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp7] \n\t" @@ -1284,10 +1284,10 @@ void ff_h264_biweight_pixels8_8_mmi(uint8_t *dst, uint8_t *src, "pmullh %[ftmp8], %[ftmp8], %[ftmp4] \n\t" "pmullh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" "pmullh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "paddsh %[ftmp7], %[ftmp7], %[ftmp5] \n\t" - "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "paddsh %[ftmp7], %[ftmp7], %[ftmp8] \n\t" "paddsh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "paddsh %[ftmp7], %[ftmp7], %[ftmp5] \n\t" + "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "psrah %[ftmp7], %[ftmp7], %[ftmp6] \n\t" "psrah %[ftmp1], %[ftmp1], %[ftmp6] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp7] \n\t" @@ -1370,8 +1370,8 @@ void ff_h264_biweight_pixels4_8_mmi(uint8_t *dst, uint8_t *src, "punpcklbh %[ftmp2], %[ftmp2], %[ftmp0] \n\t" "pmullh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" "pmullh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "paddsh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "paddsh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "psrah %[ftmp1], %[ftmp1], %[ftmp6] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" MMI_SWC1(%[ftmp1], %[dst], 0x00) diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 61839b13d6..6cdc44b5ef 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -545,7 +545,7 @@ static void check_weight(void) } // only archs that can pass test -#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC) +#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC || ARCH_MIPS) #if H264_CHECK_BIWEIGHT static void check_biweight(void) -- 2.52.0 >From 4447f77fa4572354ea5d13b27fd96eccd8063f56 Mon Sep 17 00:00:00 2001 From: Zuxy Meng <[email protected]> Date: Fri, 4 Sep 2026 21:25:24 -0700 Subject: [PATCH 4/6] avcodec/arm|aarch64/h264dsp: Fix edge cases of bi-weight for neon S16 saturating sum must be computed dot-product-first. The NEON code accumulated the offset into the dot product with wrapping multiply-accumate, so large-magnitude sums wrapped instead of saturating. Accumulate the dot product from zero (wrapping is exact: the dot product cannot overflow S16 for 8-bit with log2_denom < 7), then add the offset with a saturating add. This fixes bi-weight checkasm test for NEON. Signed-off-by: Zuxy Meng <[email protected]> --- libavcodec/aarch64/h264dsp_neon.S | 36 +++++++++++++++++++------------ libavcodec/arm/h264dsp_neon.S | 36 +++++++++++++++++++------------ tests/checkasm/h264dsp.c | 2 +- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/libavcodec/aarch64/h264dsp_neon.S b/libavcodec/aarch64/h264dsp_neon.S index c09db164b6..06c0dcbbf5 100644 --- a/libavcodec/aarch64/h264dsp_neon.S +++ b/libavcodec/aarch64/h264dsp_neon.S @@ -586,8 +586,8 @@ endfunc .macro biweight_16 macs, macd dup v0.16b, w5 dup v1.16b, w6 - mov v4.16b, v16.16b - mov v6.16b, v16.16b + movi v4.2d, #0 + movi v6.2d, #0 1: subs w3, w3, #2 ld1 {v20.16b}, [x0], x2 \macd v4.8h, v0.8b, v20.8b @@ -595,14 +595,18 @@ endfunc ld1 {v22.16b}, [x1], x2 \macs v4.8h, v1.8b, v22.8b \macs\()2 v6.8H, v1.16B, v22.16B - mov v24.16b, v16.16b + sqadd v4.8h, v4.8h, v16.8h + sqadd v6.8h, v6.8h, v16.8h + movi v24.2d, #0 ld1 {v28.16b}, [x0], x2 - mov v26.16b, v16.16b + movi v26.2d, #0 \macd v24.8h, v0.8b, v28.8b \macd\()2 v26.8H, v0.16B, v28.16B ld1 {v30.16b}, [x1], x2 \macs v24.8h, v1.8b, v30.8b \macs\()2 v26.8H, v1.16B, v30.16B + sqadd v24.8h, v24.8h, v16.8h + sqadd v26.8h, v26.8h, v16.8h sshl v4.8h, v4.8h, v18.8h sshl v6.8h, v6.8h, v18.8h sqxtun v4.8b, v4.8h @@ -611,9 +615,9 @@ endfunc sshl v26.8h, v26.8h, v18.8h sqxtun v24.8b, v24.8h sqxtun2 v24.16b, v26.8h - mov v6.16b, v16.16b + movi v6.2d, #0 st1 {v4.16b}, [x7], x2 - mov v4.16b, v16.16b + movi v4.2d, #0 st1 {v24.16b}, [x7], x2 b.ne 1b ret @@ -622,24 +626,26 @@ endfunc .macro biweight_8 macs, macd dup v0.8b, w5 dup v1.8b, w6 - mov v2.16b, v16.16b - mov v20.16b, v16.16b + movi v2.2d, #0 + movi v20.2d, #0 1: subs w3, w3, #2 ld1 {v4.8b}, [x0], x2 \macd v2.8h, v0.8b, v4.8b ld1 {v5.8b}, [x1], x2 \macs v2.8h, v1.8b, v5.8b + sqadd v2.8h, v2.8h, v16.8h ld1 {v6.8b}, [x0], x2 \macd v20.8h, v0.8b, v6.8b ld1 {v7.8b}, [x1], x2 \macs v20.8h, v1.8b, v7.8b + sqadd v20.8h, v20.8h, v16.8h sshl v2.8h, v2.8h, v18.8h sqxtun v2.8b, v2.8h sshl v20.8h, v20.8h, v18.8h sqxtun v4.8b, v20.8h - mov v20.16b, v16.16b + movi v20.2d, #0 st1 {v2.8b}, [x7], x2 - mov v2.16b, v16.16b + movi v2.2d, #0 st1 {v4.8b}, [x7], x2 b.ne 1b ret @@ -648,8 +654,8 @@ endfunc .macro biweight_4 macs, macd dup v0.8b, w5 dup v1.8b, w6 - mov v2.16b, v16.16b - mov v20.16b,v16.16b + movi v2.2d, #0 + movi v20.2d, #0 1: subs w3, w3, #4 ld1 {v4.s}[0], [x0], x2 ld1 {v4.s}[1], [x0], x2 @@ -657,6 +663,7 @@ endfunc ld1 {v5.s}[0], [x1], x2 ld1 {v5.s}[1], [x1], x2 \macs v2.8h, v1.8b, v5.8b + sqadd v2.8h, v2.8h, v16.8h b.lt 2f ld1 {v6.s}[0], [x0], x2 ld1 {v6.s}[1], [x0], x2 @@ -664,14 +671,15 @@ endfunc ld1 {v7.s}[0], [x1], x2 ld1 {v7.s}[1], [x1], x2 \macs v20.8h, v1.8b, v7.8b + sqadd v20.8h, v20.8h, v16.8h sshl v2.8h, v2.8h, v18.8h sqxtun v2.8b, v2.8h sshl v20.8h, v20.8h, v18.8h sqxtun v4.8b, v20.8h - mov v20.16b, v16.16b + movi v20.2d, #0 st1 {v2.s}[0], [x7], x2 st1 {v2.s}[1], [x7], x2 - mov v2.16b, v16.16b + movi v2.2d, #0 st1 {v4.s}[0], [x7], x2 st1 {v4.s}[1], [x7], x2 b.ne 1b diff --git a/libavcodec/arm/h264dsp_neon.S b/libavcodec/arm/h264dsp_neon.S index 975b61c8c0..ee40807784 100644 --- a/libavcodec/arm/h264dsp_neon.S +++ b/libavcodec/arm/h264dsp_neon.S @@ -295,8 +295,8 @@ endfunc .macro biweight_16 macs, macd vdup.8 d0, r4 vdup.8 d1, r5 - vmov q2, q8 - vmov q3, q8 + vmov.i64 q2, #0 + vmov.i64 q3, #0 1: subs r3, r3, #2 vld1.8 {d20-d21},[r0,:128], r2 \macd q2, d0, d20 @@ -306,9 +306,11 @@ endfunc \macs q2, d1, d22 pld [r1] \macs q3, d1, d23 - vmov q12, q8 + vqadd.s16 q2, q2, q8 + vqadd.s16 q3, q3, q8 + vmov.i64 q12, #0 vld1.8 {d28-d29},[r0,:128], r2 - vmov q13, q8 + vmov.i64 q13, #0 \macd q12, d0, d28 pld [r0] \macd q13, d0, d29 @@ -316,6 +318,8 @@ endfunc \macs q12, d1, d30 pld [r1] \macs q13, d1, d31 + vqadd.s16 q12, q12, q8 + vqadd.s16 q13, q13, q8 vshl.s16 q2, q2, q9 vshl.s16 q3, q3, q9 vqmovun.s16 d4, q2 @@ -324,9 +328,9 @@ endfunc vshl.s16 q13, q13, q9 vqmovun.s16 d24, q12 vqmovun.s16 d25, q13 - vmov q3, q8 + vmov.i64 q3, #0 vst1.8 {d4- d5}, [r6,:128], r2 - vmov q2, q8 + vmov.i64 q2, #0 vst1.8 {d24-d25},[r6,:128], r2 bne 1b pop {r4-r6, pc} @@ -335,8 +339,8 @@ endfunc .macro biweight_8 macs, macd vdup.8 d0, r4 vdup.8 d1, r5 - vmov q1, q8 - vmov q10, q8 + vmov.i64 q1, #0 + vmov.i64 q10, #0 1: subs r3, r3, #2 vld1.8 {d4},[r0,:64], r2 \macd q1, d0, d4 @@ -344,19 +348,21 @@ endfunc vld1.8 {d5},[r1,:64], r2 \macs q1, d1, d5 pld [r1] + vqadd.s16 q1, q1, q8 vld1.8 {d6},[r0,:64], r2 \macd q10, d0, d6 pld [r0] vld1.8 {d7},[r1,:64], r2 \macs q10, d1, d7 pld [r1] + vqadd.s16 q10, q10, q8 vshl.s16 q1, q1, q9 vqmovun.s16 d2, q1 vshl.s16 q10, q10, q9 vqmovun.s16 d4, q10 - vmov q10, q8 + vmov.i64 q10, #0 vst1.8 {d2},[r6,:64], r2 - vmov q1, q8 + vmov.i64 q1, #0 vst1.8 {d4},[r6,:64], r2 bne 1b pop {r4-r6, pc} @@ -365,8 +371,8 @@ endfunc .macro biweight_4 macs, macd vdup.8 d0, r4 vdup.8 d1, r5 - vmov q1, q8 - vmov q10, q8 + vmov.i64 q1, #0 + vmov.i64 q10, #0 1: subs r3, r3, #4 vld1.32 {d4[0]},[r0,:32], r2 vld1.32 {d4[1]},[r0,:32], r2 @@ -376,6 +382,7 @@ endfunc vld1.32 {d5[1]},[r1,:32], r2 \macs q1, d1, d5 pld [r1] + vqadd.s16 q1, q1, q8 blt 2f vld1.32 {d6[0]},[r0,:32], r2 vld1.32 {d6[1]},[r0,:32], r2 @@ -385,14 +392,15 @@ endfunc vld1.32 {d7[1]},[r1,:32], r2 \macs q10, d1, d7 pld [r1] + vqadd.s16 q10, q10, q8 vshl.s16 q1, q1, q9 vqmovun.s16 d2, q1 vshl.s16 q10, q10, q9 vqmovun.s16 d4, q10 - vmov q10, q8 + vmov.i64 q10, #0 vst1.32 {d2[0]},[r6,:32], r2 vst1.32 {d2[1]},[r6,:32], r2 - vmov q1, q8 + vmov.i64 q1, #0 vst1.32 {d4[0]},[r6,:32], r2 vst1.32 {d4[1]},[r6,:32], r2 bne 1b diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 6cdc44b5ef..06d7cc325c 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -545,7 +545,7 @@ static void check_weight(void) } // only archs that can pass test -#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC || ARCH_MIPS) +#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC || ARCH_MIPS || ARCH_ARM || ARCH_AARCH64) #if H264_CHECK_BIWEIGHT static void check_biweight(void) -- 2.52.0 >From 16f3002170e3fcc4d056e0786ddeab19b6f178b0 Mon Sep 17 00:00:00 2001 From: Zuxy Meng <[email protected]> Date: Fri, 4 Sep 2026 21:31:57 -0700 Subject: [PATCH 5/6] avcodec/riscv/h264dsp: Fix edge cases for bi-weight on RISCV The biweight sum (src*weights + dst*weightd + offset) must saturate to S16 after the dot product is complete, like the x86 SSE2 code does (paddsw dot product first, then paddsw offset). The RVV code added the offset first with a wrapping accumulate, so large-magnitude sums wrapped instead of saturating. Use vwmulsu.vv followed by vwmaccsu.vx and vsadd.vx to handle saturation in the correct order. This fixes bi-weight checkasm test for RISCV Signed-off-by: Zuxy Meng <[email protected]> --- libavcodec/riscv/h264dsp_rvv.S | 15 +++++++++------ tests/checkasm/h264dsp.c | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libavcodec/riscv/h264dsp_rvv.S b/libavcodec/riscv/h264dsp_rvv.S index 60015a7020..41bc72090c 100644 --- a/libavcodec/riscv/h264dsp_rvv.S +++ b/libavcodec/riscv/h264dsp_rvv.S @@ -64,17 +64,19 @@ func ff_h264_biweight_pixels_simple_8_rvv, zve32x ori a7, a7, 1 sll a7, a7, a4 addi a4, a4, 1 + vsetvli t0, zero, e8, m1, ta, ma + vmv.v.x v4, a5 # splat weights (hoisted) 1: vsetvli zero, t6, e16, m2, ta, ma vle8.v v8, (a0) addi a3, a3, -1 vle8.v v12, (a1) add a1, a1, a2 - vmv.v.x v16, a7 vsetvli zero, zero, e8, m1, ta, ma - vwmaccsu.vx v16, a5, v8 + vwmulsu.vv v16, v4, v8 vwmaccsu.vx v16, a6, v12 vsetvli zero, zero, e16, m2, ta, ma + vsadd.vx v16, v16, a7 vmax.vx v16, v16, zero vsetvli zero, zero, e8, m1, ta, ma vnclipu.wx v8, v16, a4 @@ -126,19 +128,20 @@ func ff_h264_biweight_pixels\w\()_\depth\()_rvv, zve64x ori a7, a7, 1 sll a7, a7, a4 addi a4, a4, 1 + vsetvli t0, zero, e8, m2, ta, ma + vmv.v.x v4, a5 # splat weights (hoisted) 1: vsetvli t1, a3, e\b, m2, ta, ma vlse\b\().v v8, (a0), a2 sub a3, a3, t1 vlse\b\().v v12, (a1), a2 mul t2, t1, a2 - vsetvli t0, zero, e16, m4, ta, ma - vmv.v.x v16, a7 - vsetvli zero, zero, e8, m2, ta, ma - vwmaccsu.vx v16, a5, v8 + vsetvli t0, zero, e8, m2, ta, ma + vwmulsu.vv v16, v4, v8 add a1, a1, t2 vwmaccsu.vx v16, a6, v12 vsetvli zero, zero, e16, m4, ta, ma + vsadd.vx v16, v16, a7 vmax.vx v16, v16, zero vsetvli zero, zero, e8, m2, ta, ma vnclipu.wx v8, v16, a4 diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 06d7cc325c..c410461f51 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -545,7 +545,7 @@ static void check_weight(void) } // only archs that can pass test -#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC || ARCH_MIPS || ARCH_ARM || ARCH_AARCH64) +#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC || ARCH_MIPS || ARCH_ARM || ARCH_AARCH64 || ARCH_RISCV) #if H264_CHECK_BIWEIGHT static void check_biweight(void) -- 2.52.0 >From 6ac8861117710933ccf6c7434a6f23d16327fa8b Mon Sep 17 00:00:00 2001 From: Zuxy Meng <[email protected]> Date: Fri, 4 Sep 2026 21:35:36 -0700 Subject: [PATCH 6/6] avcodec/loongarch/h264dsp: Fix edge cases for bi-weight on loongarch S16 saturating sum must be computed dot-product-first. The LSX/LASX code accumulated the offset into the dot product with wrapping vmaddwev/wod, so large-magnitude sums wrapped instead of saturating. Accumulate the dot product from zero (wrapping is exact: the dot product cannot overflow S16 for 8-bit with log2_denom < 7), then add the offset with a saturating vsadd. This fixes bi-weight checkasm test for all currently available asm implementations. Signed-off-by: Zuxy Meng <[email protected]> --- libavcodec/loongarch/h264dsp.S | 18 ++++++++++++------ tests/checkasm/h264dsp.c | 7 ------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libavcodec/loongarch/h264dsp.S b/libavcodec/loongarch/h264dsp.S index 750fe49143..6e760b666c 100644 --- a/libavcodec/loongarch/h264dsp.S +++ b/libavcodec/loongarch/h264dsp.S @@ -943,10 +943,10 @@ endfunc .macro biweight_calc _in0, _in1, _in2, _in3, _reg0, _reg1, _reg2,\ _out0, _out1, _out2, _out3 - vmov \_out0, \_reg0 - vmov \_out1, \_reg0 - vmov \_out2, \_reg0 - vmov \_out3, \_reg0 + vreplgr2vr.h \_out0, zero + vreplgr2vr.h \_out1, zero + vreplgr2vr.h \_out2, zero + vreplgr2vr.h \_out3, zero vmaddwev.h.bu.b \_out0, \_in0, \_reg1 vmaddwev.h.bu.b \_out1, \_in1, \_reg1 vmaddwev.h.bu.b \_out2, \_in2, \_reg1 @@ -955,6 +955,10 @@ endfunc vmaddwod.h.bu.b \_out1, \_in1, \_reg1 vmaddwod.h.bu.b \_out2, \_in2, \_reg1 vmaddwod.h.bu.b \_out3, \_in3, \_reg1 + vsadd.h \_out0, \_out0, \_reg0 + vsadd.h \_out1, \_out1, \_reg0 + vsadd.h \_out2, \_out2, \_reg0 + vsadd.h \_out3, \_out3, \_reg0 vssran.bu.h \_out0, \_out0, \_reg2 vssran.bu.h \_out1, \_out1, \_reg2 @@ -1225,12 +1229,14 @@ function ff_biweight_h264_pixels\w\()_8_lasx .endm .macro biweight_calc_lasx _in0, _in1, _reg0, _reg1, _reg2, _out0, _out1 - xmov \_out0, \_reg0 - xmov \_out1, \_reg0 + xvreplgr2vr.h \_out0, zero + xvreplgr2vr.h \_out1, zero xvmaddwev.h.bu.b \_out0, \_in0, \_reg1 xvmaddwev.h.bu.b \_out1, \_in1, \_reg1 xvmaddwod.h.bu.b \_out0, \_in0, \_reg1 xvmaddwod.h.bu.b \_out1, \_in1, \_reg1 + xvsadd.h \_out0, \_out0, \_reg0 + xvsadd.h \_out1, \_out1, \_reg0 xvssran.bu.h \_out0, \_out0, \_reg2 xvssran.bu.h \_out1, \_out1, \_reg2 diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index c410461f51..f44360fb53 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -544,10 +544,6 @@ static void check_weight(void) } } -// only archs that can pass test -#define H264_CHECK_BIWEIGHT (ARCH_X86 || ARCH_PPC || ARCH_MIPS || ARCH_ARM || ARCH_AARCH64 || ARCH_RISCV) - -#if H264_CHECK_BIWEIGHT static void check_biweight(void) { LOCAL_ALIGNED_16(uint8_t, dst, [32 * 32 * 2]); @@ -614,7 +610,6 @@ static void check_biweight(void) } } } -#endif void checkasm_check_h264dsp(void) { @@ -632,8 +627,6 @@ void checkasm_check_h264dsp(void) check_weight(); report("weight"); -#if H264_CHECK_BIWEIGHT check_biweight(); report("biweight"); -#endif } -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
