1/*
2 * ARM NEON optimised FFT
3 *
4 * Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
5 * Copyright (c) 2009 Naotoshi Nojiri
6 *
7 * This algorithm (though not any of the implementation details) is
8 * based on libdjbfft by D. J. Bernstein.
9 *
10 * This file is part of Libav.
11 *
12 * Libav 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.
16 *
17 * Libav 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.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with Libav; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26
27#include "asm.S"
28
29#define M_SQRT1_2 0.70710678118654752440
30
31
32function fft4_neon
33        vld1.32         {d0-d3}, [r0,:128]
34
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
40        vadd.f32        d1,  d6,  d7
41        vsub.f32        d3,  d6,  d7
42        vadd.f32        d0,  d4,  d5
43        vsub.f32        d2,  d4,  d5
44
45        vst1.32         {d0-d3}, [r0,:128]
46
47        bx              lr
48endfunc
49
50function fft8_neon
51        mov             r1,  r0
52        vld1.32         {d0-d3},   [r1,:128]!
53        vld1.32         {d16-d19}, [r1,:128]
54
55        movw            r2,  #0x04f3            @ sqrt(1/2)
56        movt            r2,  #0x3f35
57        eor             r3,  r2,  #1<<31
58        vdup.32         d31, r2
59
60        vext.32         q11, q1,  q1,  #1       @ i2,r3,i3,r2
61        vadd.f32        d4,  d16, d17           @ r4+r5,i4+i5
62        vmov            d28, r3,  r2
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
66        vrev64.32       d29, d28
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
76        vadd.f32        d0,  d20, d21
77        vsub.f32        d2,  d20, d21
78        vadd.f32        d1,  d22, d23
79        vrev64.32       q13, q13
80        vsub.f32        d3,  d22, d23
81        vsub.f32        d6,  d6,  d7
82        vadd.f32        d24, d24, d26           @ a2r+a2i,a2i-a2r   t1,t2
83        vadd.f32        d25, d25, d27           @ a3r-a3i,a3i+a3r   t5,t6
84        vadd.f32        d7,  d4,  d5
85        vsub.f32        d18, d2,  d6
86        vext.32         q13, q12, q12, #1
87        vadd.f32        d2,  d2,  d6
88        vsub.f32        d16, d0,  d7
89        vadd.f32        d5,  d25, d24
90        vsub.f32        d4,  d26, d27
91        vadd.f32        d0,  d0,  d7
92        vsub.f32        d17, d1,  d5
93        vsub.f32        d19, d3,  d4
94        vadd.f32        d3,  d3,  d4
95        vadd.f32        d1,  d1,  d5
96
97        vst1.32         {d16-d19}, [r1,:128]
98        vst1.32         {d0-d3},   [r0,:128]
99
100        bx              lr
101endfunc
102
103function fft16_neon
104        movrel          r1, mppm
105        vld1.32         {d16-d19}, [r0,:128]!   @ q8{r0,i0,r1,i1} q9{r2,i2,r3,i3}
106        pld             [r0, #32]
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
114
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}
126        vrev64.32       q12, q12
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}
129        vzip.32         q10, q11
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
135        sub             r0,  r0,  #96
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        movrel          r2,  X(ff_cos_16)
147        vsub.f32        q13, q12, q13           @ {t3,t4,t7,t8}
148        vrev64.32       d1,  d1
149        vsub.f32        q15, q14, q15           @ {t3a,t4a,t7a,t8a}
150        vrev64.32       d3,  d3
151        movrel          r3,  pmmp
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]
161        vrev64.32       q1,  q14
162        vmul.f32        q14, q14, d4[1]
163        vmul.f32        q1,  q1,  q3
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}
166        vzip.32         q12, q14
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}
174        mov             r1,  #32
175        vadd.f32        q10, q10, q1            @ {r4,r5,i4,i5}
176        vrev64.32       q0,  q13
177        vmul.f32        q13, q13, d5[0]
178        vrev64.32       q1,  q15
179        vmul.f32        q15, q15, d5[1]
180        vst2.32         {d16-d17},[r0,:128], r1
181        vmul.f32        q0,  q0,  q3
182        vst2.32         {d20-d21},[r0,:128], r1
183        vmul.f32        q1,  q1,  q3
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]
188        vzip.32         q13, q15
189        sub             r0, r0, #80
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]
202        bx              lr
203endfunc
204
205function fft_pass_neon
206        push            {r4-r6,lr}
207        mov             r6,  r2                 @ n
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
211        add             r3,  r2,  r4
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]}
216        movrel          r12, pmmp
217        vld1.32         {d22-d23},[r3,:128]     @ {z[o3],z[o3+1]}
218        add             r5,  r5,  r1            @ wim
219        vld1.32         {d6-d7},  [r12,:128]    @ pmmp
220        vswp            d21, d22
221        vld1.32         {d4},     [r1,:64]!     @ {wre[0],wre[1]}
222        sub             r5,  r5,  #4            @ wim--
223        vrev64.32       q1,  q11
224        vmul.f32        q11, q11, d4[1]
225        vmul.f32        q1,  q1,  q3
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]}
229        sub             r6, r6, #1              @ n--
230        vld2.32         {d18-d19},[r4,:128]     @ {z[o1],z[o1+1]}
231        vzip.32         q10, q11
232        vadd.f32        d0,  d22, d20
233        vadd.f32        d1,  d21, d23
234        vsub.f32        d2,  d21, d23
235        vsub.f32        d3,  d22, d20
236        vsub.f32        q10, q8,  q0
237        vadd.f32        q8,  q8,  q0
238        vsub.f32        q11, q9,  q1
239        vadd.f32        q9,  q9,  q1
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
2451:
246        vld1.32         {d20-d21},[r2,:128]     @ {z[o2],z[o2+1]}
247        vld1.32         {d22-d23},[r3,:128]     @ {z[o3],z[o3+1]}
248        vswp            d21, d22
249        vld1.32         {d4}, [r1]!             @ {wre[0],wre[1]}
250        vrev64.32       q0,  q10
251        vmul.f32        q10, q10, d4[0]
252        vrev64.32       q1,  q11
253        vmul.f32        q11, q11, d4[1]
254        vld1.32         {d5}, [r5]              @ {wim[-1],wim[0]}
255        vmul.f32        q0,  q0,  q3
256        sub             r5,  r5,  #8            @ wim -= 2
257        vmul.f32        q1,  q1,  q3
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]}
263        vzip.32         q10, q11
264        vadd.f32        d0,  d22, d20
265        vadd.f32        d1,  d21, d23
266        vsub.f32        d2,  d21, d23
267        vsub.f32        d3,  d22, d20
268        vsub.f32        q10, q8,  q0
269        vadd.f32        q8,  q8,  q0
270        vsub.f32        q11, q9,  q1
271        vadd.f32        q9,  q9,  q1
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]}
276        bne             1b
277
278        pop             {r4-r6,pc}
279endfunc
280
281.macro  def_fft n, n2, n4
282        .align 6
283function fft\n\()_neon
284        push            {r4, lr}
285        mov             r4,  r0
286        bl              fft\n2\()_neon
287        add             r0,  r4,  #\n4*2*8
288        bl              fft\n4\()_neon
289        add             r0,  r4,  #\n4*3*8
290        bl              fft\n4\()_neon
291        mov             r0,  r4
292        pop             {r4, lr}
293        movrel          r1,  X(ff_cos_\n)
294        mov             r2,  #\n4/2
295        b               fft_pass_neon
296endfunc
297.endm
298
299        def_fft    32,    16,     8
300        def_fft    64,    32,    16
301        def_fft   128,    64,    32
302        def_fft   256,   128,    64
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
311
312function ff_fft_calc_neon, export=1
313        ldr             r2,  [r0]
314        sub             r2,  r2,  #2
315        movrel          r3,  fft_tab_neon
316        ldr             r3,  [r3, r2, lsl #2]
317        mov             r0,  r1
318        bx              r3
319endfunc
320
321function ff_fft_permute_neon, export=1
322        push            {r4,lr}
323        mov             r12, #1
324        ldr             r2,  [r0]       @ nbits
325        ldr             r3,  [r0, #12]  @ tmp_buf
326        ldr             r0,  [r0, #8]   @ revtab
327        lsl             r12, r12, r2
328        mov             r2,  r12
3291:
330        vld1.32         {d0-d1}, [r1,:128]!
331        ldr             r4,  [r0], #4
332        uxth            lr,  r4
333        uxth            r4,  r4,  ror #16
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]
338        subs            r12, r12, #2
339        bgt             1b
340
341        sub             r1,  r1,  r2,  lsl #3
3421:
343        vld1.32         {d0-d3}, [r3,:128]!
344        vst1.32         {d0-d3}, [r1,:128]!
345        subs            r2,  r2,  #4
346        bgt             1b
347
348        pop             {r4,pc}
349endfunc
350
351const   fft_tab_neon
352        .word fft4_neon
353        .word fft8_neon
354        .word fft16_neon
355        .word fft32_neon
356        .word fft64_neon
357        .word fft128_neon
358        .word fft256_neon
359        .word fft512_neon
360        .word fft1024_neon
361        .word fft2048_neon
362        .word fft4096_neon
363        .word fft8192_neon
364        .word fft16384_neon
365        .word fft32768_neon
366        .word fft65536_neon
367endconst
368
369const   pmmp, align=4
370        .float          +1.0, -1.0, -1.0, +1.0
371endconst
372
373const   mppm, align=4
374        .float          -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2
375endconst
376