2 * ARM NEON optimised FFT
4 * Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
5 * Copyright (c) 2009 Naotoshi Nojiri
7 * This algorithm (though not any of the implementation details) is
8 * based on libdjbfft by D. J. Bernstein.
10 * This file is part of FFmpeg.
12 * FFmpeg is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * FFmpeg is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with FFmpeg; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavutil/arm/asm.S"
29 #define M_SQRT1_2 0.70710678118654752440
33 vld1.32 {d0-d3}, [r0,:128]
35 vext.32 q8, q1, q1, #1 @ i2,r3 d3=i3,r2
36 vsub.f32 d6, d0, d1 @ r0-r1,i0-i1
37 vsub.f32 d7, d16, d17 @ r3-r2,i2-i3
38 vadd.f32 d4, d0, d1 @ r0+r1,i0+i1
39 vadd.f32 d5, d2, d3 @ i2+i3,r2+r3
45 vst1.32 {d0-d3}, [r0,:128]
52 vld1.32 {d0-d3}, [r1,:128]!
53 vld1.32 {d16-d19}, [r1,:128]
55 movw r2, #0x04f3 @ sqrt(1/2)
60 vext.32 q11, q1, q1, #1 @ i2,r3,i3,r2
61 vadd.f32 d4, d16, d17 @ r4+r5,i4+i5
63 vadd.f32 d5, d18, d19 @ r6+r7,i6+i7
64 vsub.f32 d17, d16, d17 @ r4-r5,i4-i5
65 vsub.f32 d19, d18, d19 @ r6-r7,i6-i7
67 vadd.f32 d20, d0, d1 @ r0+r1,i0+i1
68 vadd.f32 d21, d2, d3 @ r2+r3,i2+i3
69 vmul.f32 d26, d17, d28 @ -a2r*w,a2i*w
70 vext.32 q3, q2, q2, #1
71 vmul.f32 d27, d19, d29 @ a3r*w,-a3i*w
72 vsub.f32 d23, d22, d23 @ i2-i3,r3-r2
73 vsub.f32 d22, d0, d1 @ r0-r1,i0-i1
74 vmul.f32 d24, d17, d31 @ a2r*w,a2i*w
75 vmul.f32 d25, d19, d31 @ a3r*w,a3i*w
82 vadd.f32 d24, d24, d26 @ a2r+a2i,a2i-a2r t1,t2
83 vadd.f32 d25, d25, d27 @ a3r-a3i,a3i+a3r t5,t6
86 vext.32 q13, q12, q12, #1
97 vst1.32 {d16-d19}, [r1,:128]
98 vst1.32 {d0-d3}, [r0,:128]
105 vld1.32 {d16-d19}, [r0,:128]! @ q8{r0,i0,r1,i1} q9{r2,i2,r3,i3}
107 vld1.32 {d2-d3}, [r1,:128]
108 vext.32 q13, q9, q9, #1
109 vld1.32 {d22-d25}, [r0,:128]! @ q11{r4,i4,r5,i5} q12{r6,i5,r7,i7}
110 vadd.f32 d4, d16, d17
111 vsub.f32 d5, d16, d17
112 vadd.f32 d18, d18, d19
113 vsub.f32 d19, d26, d27
115 vadd.f32 d20, d22, d23
116 vsub.f32 d22, d22, d23
117 vsub.f32 d23, d24, d25
118 vadd.f32 q8, q2, q9 @ {r0,i0,r1,i1}
119 vadd.f32 d21, d24, d25
120 vmul.f32 d24, d22, d2
121 vsub.f32 q9, q2, q9 @ {r2,i2,r3,i3}
122 vmul.f32 d25, d23, d3
123 vuzp.32 d16, d17 @ {r0,r1,i0,i1}
124 vmul.f32 q1, q11, d2[1]
125 vuzp.32 d18, d19 @ {r2,r3,i2,i3}
127 vadd.f32 q11, q12, q1 @ {t1a,t2a,t5,t6}
128 vld1.32 {d24-d27}, [r0,:128]! @ q12{r8,i8,r9,i9} q13{r10,i10,r11,i11}
130 vld1.32 {d28-d31}, [r0,:128] @ q14{r12,i12,r13,i13} q15{r14,i14,r15,i15}
131 vadd.f32 d0, d22, d20
132 vadd.f32 d1, d21, d23
133 vsub.f32 d2, d21, d23
134 vsub.f32 d3, d22, d20
136 vext.32 q13, q13, q13, #1
137 vsub.f32 q10, q8, q0 @ {r4,r5,i4,i5}
138 vadd.f32 q8, q8, q0 @ {r0,r1,i0,i1}
139 vext.32 q15, q15, q15, #1
140 vsub.f32 q11, q9, q1 @ {r6,r7,i6,i7}
141 vswp d25, d26 @ q12{r8,i8,i10,r11} q13{r9,i9,i11,r10}
142 vadd.f32 q9, q9, q1 @ {r2,r3,i2,i3}
143 vswp d29, d30 @ q14{r12,i12,i14,r15} q15{r13,i13,i15,r14}
144 vadd.f32 q0, q12, q13 @ {t1,t2,t5,t6}
145 vadd.f32 q1, q14, q15 @ {t1a,t2a,t5a,t6a}
146 movrelx r2, X(ff_cos_16)
147 vsub.f32 q13, q12, q13 @ {t3,t4,t7,t8}
149 vsub.f32 q15, q14, q15 @ {t3a,t4a,t7a,t8a}
152 vswp d1, d26 @ q0{t1,t2,t3,t4} q13{t6,t5,t7,t8}
153 vswp d3, d30 @ q1{t1a,t2a,t3a,t4a} q15{t6a,t5a,t7a,t8a}
154 vadd.f32 q12, q0, q13 @ {r8,i8,r9,i9}
155 vadd.f32 q14, q1, q15 @ {r12,i12,r13,i13}
156 vld1.32 {d4-d5}, [r2,:64]
157 vsub.f32 q13, q0, q13 @ {r10,i10,r11,i11}
158 vsub.f32 q15, q1, q15 @ {r14,i14,r15,i15}
159 vswp d25, d28 @ q12{r8,i8,r12,i12} q14{r9,i9,r13,i13}
160 vld1.32 {d6-d7}, [r3,:128]
162 vmul.f32 q14, q14, d4[1]
164 vmla.f32 q14, q1, d5[1] @ {t1a,t2a,t5a,t6a}
165 vswp d27, d30 @ q13{r10,i10,r14,i14} q15{r11,i11,r15,i15}
167 vadd.f32 d0, d28, d24
168 vadd.f32 d1, d25, d29
169 vsub.f32 d2, d25, d29
170 vsub.f32 d3, d28, d24
171 vsub.f32 q12, q8, q0 @ {r8,r9,i8,i9}
172 vadd.f32 q8, q8, q0 @ {r0,r1,i0,i1}
173 vsub.f32 q14, q10, q1 @ {r12,r13,i12,i13}
175 vadd.f32 q10, q10, q1 @ {r4,r5,i4,i5}
177 vmul.f32 q13, q13, d5[0]
179 vmul.f32 q15, q15, d5[1]
180 vst2.32 {d16-d17},[r0,:128], r1
182 vst2.32 {d20-d21},[r0,:128], r1
184 vmla.f32 q13, q0, d5[0] @ {t1,t2,t5,t6}
185 vmla.f32 q15, q1, d4[1] @ {t1a,t2a,t5a,t6a}
186 vst2.32 {d24-d25},[r0,:128], r1
187 vst2.32 {d28-d29},[r0,:128]
190 vadd.f32 d0, d30, d26
191 vadd.f32 d1, d27, d31
192 vsub.f32 d2, d27, d31
193 vsub.f32 d3, d30, d26
194 vsub.f32 q13, q9, q0 @ {r10,r11,i10,i11}
195 vadd.f32 q9, q9, q0 @ {r2,r3,i2,i3}
196 vsub.f32 q15, q11, q1 @ {r14,r15,i14,i15}
197 vadd.f32 q11, q11, q1 @ {r6,r7,i6,i7}
198 vst2.32 {d18-d19},[r0,:128], r1
199 vst2.32 {d22-d23},[r0,:128], r1
200 vst2.32 {d26-d27},[r0,:128], r1
201 vst2.32 {d30-d31},[r0,:128]
205 function fft_pass_neon
208 lsl r5, r2, #3 @ 2 * n * sizeof FFTSample
209 lsl r4, r2, #4 @ 2 * n * sizeof FFTComplex
210 lsl r2, r2, #5 @ 4 * n * sizeof FFTComplex
212 add r4, r4, r0 @ &z[o1]
213 add r2, r2, r0 @ &z[o2]
214 add r3, r3, r0 @ &z[o3]
215 vld1.32 {d20-d21},[r2,:128] @ {z[o2],z[o2+1]}
217 vld1.32 {d22-d23},[r3,:128] @ {z[o3],z[o3+1]}
219 vld1.32 {d6-d7}, [r12,:128] @ pmmp
221 vld1.32 {d4}, [r1,:64]! @ {wre[0],wre[1]}
222 sub r5, r5, #4 @ wim--
224 vmul.f32 q11, q11, d4[1]
226 vld1.32 {d5[0]}, [r5,:32] @ d5[0] = wim[-1]
227 vmla.f32 q11, q1, d5[0] @ {t1a,t2a,t5a,t6a}
228 vld2.32 {d16-d17},[r0,:128] @ {z[0],z[1]}
230 vld2.32 {d18-d19},[r4,:128] @ {z[o1],z[o1+1]}
232 vadd.f32 d0, d22, d20
233 vadd.f32 d1, d21, d23
234 vsub.f32 d2, d21, d23
235 vsub.f32 d3, d22, d20
240 vst2.32 {d20-d21},[r2,:128]! @ {z[o2],z[o2+1]}
241 vst2.32 {d16-d17},[r0,:128]! @ {z[0],z[1]}
242 vst2.32 {d22-d23},[r3,:128]! @ {z[o3],z[o3+1]}
243 vst2.32 {d18-d19},[r4,:128]! @ {z[o1],z[o1+1]}
244 sub r5, r5, #8 @ wim -= 2
246 vld1.32 {d20-d21},[r2,:128] @ {z[o2],z[o2+1]}
247 vld1.32 {d22-d23},[r3,:128] @ {z[o3],z[o3+1]}
249 vld1.32 {d4}, [r1]! @ {wre[0],wre[1]}
251 vmul.f32 q10, q10, d4[0]
253 vmul.f32 q11, q11, d4[1]
254 vld1.32 {d5}, [r5] @ {wim[-1],wim[0]}
256 sub r5, r5, #8 @ wim -= 2
258 vmla.f32 q10, q0, d5[1] @ {t1,t2,t5,t6}
259 vmla.f32 q11, q1, d5[0] @ {t1a,t2a,t5a,t6a}
260 vld2.32 {d16-d17},[r0,:128] @ {z[0],z[1]}
261 subs r6, r6, #1 @ n--
262 vld2.32 {d18-d19},[r4,:128] @ {z[o1],z[o1+1]}
264 vadd.f32 d0, d22, d20
265 vadd.f32 d1, d21, d23
266 vsub.f32 d2, d21, d23
267 vsub.f32 d3, d22, d20
272 vst2.32 {d20-d21}, [r2,:128]! @ {z[o2],z[o2+1]}
273 vst2.32 {d16-d17}, [r0,:128]! @ {z[0],z[1]}
274 vst2.32 {d22-d23}, [r3,:128]! @ {z[o3],z[o3+1]}
275 vst2.32 {d18-d19}, [r4,:128]! @ {z[o1],z[o1+1]}
281 .macro def_fft n, n2, n4
283 function fft\n\()_neon
293 movrelx r1, X(ff_cos_\n)
303 def_fft 512, 256, 128
304 def_fft 1024, 512, 256
305 def_fft 2048, 1024, 512
306 def_fft 4096, 2048, 1024
307 def_fft 8192, 4096, 2048
308 def_fft 16384, 8192, 4096
309 def_fft 32768, 16384, 8192
310 def_fft 65536, 32768, 16384
312 function ff_fft_calc_neon, export=1
315 movrel r3, fft_tab_neon
316 ldr r3, [r3, r2, lsl #2]
321 function ff_fft_permute_neon, export=1
325 ldr r3, [r0, #12] @ tmp_buf
326 ldr r0, [r0, #8] @ revtab
330 vld1.32 {d0-d1}, [r1,:128]!
334 add lr, r3, lr, lsl #3
335 add r4, r3, r4, lsl #3
336 vst1.32 {d0}, [lr,:64]
337 vst1.32 {d1}, [r4,:64]
341 sub r1, r1, r2, lsl #3
343 vld1.32 {d0-d3}, [r3,:128]!
344 vst1.32 {d0-d3}, [r1,:128]!
351 const fft_tab_neon, relocate=1
370 .float +1.0, -1.0, -1.0, +1.0
374 .float -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2