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]

Reply via email to