Commit 8105ae2afe for ffmpeg

commit 8105ae2afe2c4182a4ad44b1b9c45a3146f0c0b1
Author: Jeongkeun Kim <variety0724@gmail.com>
Date:   Fri Jun 26 09:30:09 2026 +0900

    avcodec/aarch64: add NEON lfe_fir_fixed for DCA DSP

    Add a NEON implementation of the fixed-point DCA LFE FIR interpolation
    filter.

    Each vector lane holds one of four consecutive LFE samples, so the
    filter coefficients are used as by-element multipliers and can be
    loaded contiguously without any permutes. One load of c[8j..8j+7] and
    c[248-8j..255-8j] covers outputs j, 32+j, 31-j and 63-j. The 8-tap
    sums are accumulated in 64 bits with SMULL/SMLAL, rounded with SQRSHRN,
    clipped to 23 bits with SQSHL/SSHR and written with ST2 lane stores.

    Recent clang versions auto-vectorize the C version, so the speedup
    depends a lot on the compiler. On Neoverse-N1 (64 LFE samples):

      C compiler   speedup
      clang 14     4.84x
      gcc 11       1.75x
      clang 20     1.21x
      clang 22     1.21x

    Signed-off-by: Jeongkeun Kim <variety0724@gmail.com>

diff --git a/libavcodec/aarch64/dcadsp_init_aarch64.c b/libavcodec/aarch64/dcadsp_init_aarch64.c
index acb4194e9d..7d80c160e3 100644
--- a/libavcodec/aarch64/dcadsp_init_aarch64.c
+++ b/libavcodec/aarch64/dcadsp_init_aarch64.c
@@ -32,6 +32,8 @@ void ff_lfe_fir1_float_neon(float *pcm_samples, const int32_t *lfe_samples,
                             const float *filter_coeff, ptrdiff_t npcmblocks);
 void ff_lfe_x96_fixed_neon(int32_t *dst, const int32_t *src,
                            int32_t *hist, ptrdiff_t len);
+void ff_lfe_fir_fixed_neon(int32_t *pcm_samples, const int32_t *lfe_samples,
+                           const int32_t *filter_coeff, ptrdiff_t npcmblocks);

 av_cold void ff_dcadsp_init_aarch64(DCADSPContext *s)
 {
@@ -41,5 +43,6 @@ av_cold void ff_dcadsp_init_aarch64(DCADSPContext *s)
         s->lfe_fir_float[0] = ff_lfe_fir0_float_neon;
         s->lfe_fir_float[1] = ff_lfe_fir1_float_neon;
         s->lfe_x96_fixed    = ff_lfe_x96_fixed_neon;
+        s->lfe_fir_fixed    = ff_lfe_fir_fixed_neon;
     }
 }
diff --git a/libavcodec/aarch64/dcadsp_neon.S b/libavcodec/aarch64/dcadsp_neon.S
index bc7e35f993..b059108283 100644
--- a/libavcodec/aarch64/dcadsp_neon.S
+++ b/libavcodec/aarch64/dcadsp_neon.S
@@ -149,3 +149,151 @@ function ff_lfe_x96_fixed_neon, export=1
         st1             {v2.s}[3], [x2]
         ret
 endfunc
+
+// Lanes hold four consecutive LFE samples. Outputs:
+// ra = pcm[j], rb = pcm[32 + j], rc = pcm[31 - j], rd = pcm[63 - j]
+.macro lfe_fir_fixed_pair ra, rb, rc, rd
+        ldp             q8,  q9,  [x8],  #32
+        ldp             q10, q11, [x9],  #-32
+        smull           v0.2d,  v16.2s, v8.s[0]
+        smull2          v1.2d,  v16.4s, v8.s[0]
+        smull           v2.2d,  v16.2s, v11.s[3]
+        smull2          v3.2d,  v16.4s, v11.s[3]
+        smull           v4.2d,  v16.2s, v10.s[0]
+        smull2          v5.2d,  v16.4s, v10.s[0]
+        smull           v6.2d,  v16.2s, v9.s[3]
+        smull2          v7.2d,  v16.4s, v9.s[3]
+        smlal           v0.2d,  v17.2s, v8.s[1]
+        smlal2          v1.2d,  v17.4s, v8.s[1]
+        smlal           v2.2d,  v17.2s, v11.s[2]
+        smlal2          v3.2d,  v17.4s, v11.s[2]
+        smlal           v4.2d,  v17.2s, v10.s[1]
+        smlal2          v5.2d,  v17.4s, v10.s[1]
+        smlal           v6.2d,  v17.2s, v9.s[2]
+        smlal2          v7.2d,  v17.4s, v9.s[2]
+        smlal           v0.2d,  v18.2s, v8.s[2]
+        smlal2          v1.2d,  v18.4s, v8.s[2]
+        smlal           v2.2d,  v18.2s, v11.s[1]
+        smlal2          v3.2d,  v18.4s, v11.s[1]
+        smlal           v4.2d,  v18.2s, v10.s[2]
+        smlal2          v5.2d,  v18.4s, v10.s[2]
+        smlal           v6.2d,  v18.2s, v9.s[1]
+        smlal2          v7.2d,  v18.4s, v9.s[1]
+        smlal           v0.2d,  v19.2s, v8.s[3]
+        smlal2          v1.2d,  v19.4s, v8.s[3]
+        smlal           v2.2d,  v19.2s, v11.s[0]
+        smlal2          v3.2d,  v19.4s, v11.s[0]
+        smlal           v4.2d,  v19.2s, v10.s[3]
+        smlal2          v5.2d,  v19.4s, v10.s[3]
+        smlal           v6.2d,  v19.2s, v9.s[0]
+        smlal2          v7.2d,  v19.4s, v9.s[0]
+        smlal           v0.2d,  v20.2s, v9.s[0]
+        smlal2          v1.2d,  v20.4s, v9.s[0]
+        smlal           v2.2d,  v20.2s, v10.s[3]
+        smlal2          v3.2d,  v20.4s, v10.s[3]
+        smlal           v4.2d,  v20.2s, v11.s[0]
+        smlal2          v5.2d,  v20.4s, v11.s[0]
+        smlal           v6.2d,  v20.2s, v8.s[3]
+        smlal2          v7.2d,  v20.4s, v8.s[3]
+        smlal           v0.2d,  v21.2s, v9.s[1]
+        smlal2          v1.2d,  v21.4s, v9.s[1]
+        smlal           v2.2d,  v21.2s, v10.s[2]
+        smlal2          v3.2d,  v21.4s, v10.s[2]
+        smlal           v4.2d,  v21.2s, v11.s[1]
+        smlal2          v5.2d,  v21.4s, v11.s[1]
+        smlal           v6.2d,  v21.2s, v8.s[2]
+        smlal2          v7.2d,  v21.4s, v8.s[2]
+        smlal           v0.2d,  v22.2s, v9.s[2]
+        smlal2          v1.2d,  v22.4s, v9.s[2]
+        smlal           v2.2d,  v22.2s, v10.s[1]
+        smlal2          v3.2d,  v22.4s, v10.s[1]
+        smlal           v4.2d,  v22.2s, v11.s[2]
+        smlal2          v5.2d,  v22.4s, v11.s[2]
+        smlal           v6.2d,  v22.2s, v8.s[1]
+        smlal2          v7.2d,  v22.4s, v8.s[1]
+        smlal           v0.2d,  v23.2s, v9.s[3]
+        smlal2          v1.2d,  v23.4s, v9.s[3]
+        smlal           v2.2d,  v23.2s, v10.s[0]
+        smlal2          v3.2d,  v23.4s, v10.s[0]
+        smlal           v4.2d,  v23.2s, v11.s[3]
+        smlal2          v5.2d,  v23.4s, v11.s[3]
+        smlal           v6.2d,  v23.2s, v8.s[0]
+        smlal2          v7.2d,  v23.4s, v8.s[0]
+        sqrshrn         \ra\().2s, v0.2d, #23
+        sqrshrn         \rb\().2s, v2.2d, #23
+        sqrshrn         \rc\().2s, v4.2d, #23
+        sqrshrn         \rd\().2s, v6.2d, #23
+        sqrshrn2        \ra\().4s, v1.2d, #23
+        sqrshrn2        \rb\().4s, v3.2d, #23
+        sqrshrn2        \rc\().4s, v5.2d, #23
+        sqrshrn2        \rd\().4s, v7.2d, #23
+        sqshl           \ra\().4s, \ra\().4s, #8
+        sqshl           \rb\().4s, \rb\().4s, #8
+        sqshl           \rc\().4s, \rc\().4s, #8
+        sqshl           \rd\().4s, \rd\().4s, #8
+        sshr            \ra\().4s, \ra\().4s, #8
+        sshr            \rb\().4s, \rb\().4s, #8
+        sshr            \rc\().4s, \rc\().4s, #8
+        sshr            \rd\().4s, \rd\().4s, #8
+.endm
+
+function ff_lfe_fir_fixed_neon, export=1
+        stp             d8,  d9,  [sp, #-32]!
+        stp             d10, d11, [sp, #16]
+        lsr             x3,  x3,  #3
+        sub             x1,  x1,  #(8*4)
+        mov             x15, #-136
+        mov             x16, #128
+        mov             x17, #-120
+.Louter_fixed:
+        ld1             {v24.4s}, [x1]
+        ldr             q20, [x1, #16]
+        ldr             q16, [x1, #32]
+        add             x1,  x1,  #16
+        ext             v17.16b, v20.16b, v16.16b, #12
+        ext             v18.16b, v20.16b, v16.16b, #8
+        ext             v19.16b, v20.16b, v16.16b, #4
+        ext             v21.16b, v24.16b, v20.16b, #12
+        ext             v22.16b, v24.16b, v20.16b, #8
+        ext             v23.16b, v24.16b, v20.16b, #4
+
+        mov             x8,  x2
+        add             x9,  x2,  #(248*4)
+        mov             x4,  x0
+        add             x5,  x0,  #(64*4)
+        add             x6,  x0,  #(128*4)
+        add             x7,  x0,  #(192*4)
+        add             x10, x0,  #(30*4)
+        add             x11, x0,  #(94*4)
+        add             x12, x0,  #(158*4)
+        add             x13, x0,  #(222*4)
+.Linner_fixed:
+        lfe_fir_fixed_pair v24, v26, v29, v31
+        lfe_fir_fixed_pair v25, v27, v28, v30
+        cmp             x8,  x9
+        st2             {v24.s, v25.s}[0], [x4],  x16
+        st2             {v24.s, v25.s}[1], [x5],  x16
+        st2             {v24.s, v25.s}[2], [x6],  x16
+        st2             {v24.s, v25.s}[3], [x7],  x16
+        st2             {v26.s, v27.s}[0], [x4],  x17
+        st2             {v26.s, v27.s}[1], [x5],  x17
+        st2             {v26.s, v27.s}[2], [x6],  x17
+        st2             {v26.s, v27.s}[3], [x7],  x17
+        st2             {v28.s, v29.s}[0], [x10], x16
+        st2             {v28.s, v29.s}[1], [x11], x16
+        st2             {v28.s, v29.s}[2], [x12], x16
+        st2             {v28.s, v29.s}[3], [x13], x16
+        st2             {v30.s, v31.s}[0], [x10], x15
+        st2             {v30.s, v31.s}[1], [x11], x15
+        st2             {v30.s, v31.s}[2], [x12], x15
+        st2             {v30.s, v31.s}[3], [x13], x15
+        b.lt            .Linner_fixed
+
+        subs            x3,  x3,  #1
+        add             x0,  x0,  #(256*4)
+        b.gt            .Louter_fixed
+
+        ldp             d10, d11, [sp, #16]
+        ldp             d8,  d9,  [sp], #32
+        ret
+endfunc