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