PPC: convert Altivec FFT to pure assembler
[ffmpeg.git] / libavcodec / ppc / fft_altivec_s.S
1 /*
2  * FFT transform with Altivec optimizations
3  * Copyright (c) 2009 Loren Merritt
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /*
23  * These functions are not individually interchangeable with the C versions.
24  * While C takes arrays of FFTComplex, Altivec leaves intermediate results
25  * in blocks as convenient to the vector size.
26  * i.e. {4x real, 4x imaginary, 4x real, ...}
27  *
28  * I ignore standard calling convention.
29  * Instead, the following registers are treated as global constants:
30  * v14: zero
31  * v15..v18: cosines
32  * v19..v29: permutations
33  * r9: 16
34  * r12: ff_cos_tabs
35  * and the rest are free for local use.
36  */
37
38 #include "config.h"
39 #include "asm.S"
40
41 .text
42
43 .macro addi2 ra, imm // add 32-bit immediate
44 .if \imm & 0xffff
45     addi \ra, \ra, \imm@l
46 .endif
47 .if (\imm+0x8000)>>16
48     addis \ra, \ra, \imm@ha
49 .endif
50 .endm
51
52 .macro FFT4 a0, a1, a2, a3 // in:0-1 out:2-3
53     vperm   \a2,\a0,\a1,v20 // vcprm(0,1,s2,s1) // {r0,i0,r3,i2}
54     vperm   \a3,\a0,\a1,v21 // vcprm(2,3,s0,s3) // {r1,i1,r2,i3}
55     vaddfp  \a0,\a2,\a3                         // {t1,t2,t6,t5}
56     vsubfp  \a1,\a2,\a3                         // {t3,t4,t8,t7}
57     vmrghw  \a2,\a0,\a1     // vcprm(0,s0,1,s1) // {t1,t3,t2,t4}
58     vperm   \a3,\a0,\a1,v22 // vcprm(2,s3,3,s2) // {t6,t7,t5,t8}
59     vaddfp  \a0,\a2,\a3                         // {r0,r1,i0,i1}
60     vsubfp  \a1,\a2,\a3                         // {r2,r3,i2,i3}
61     vperm   \a2,\a0,\a1,v23 // vcprm(0,1,s0,s1) // {r0,r1,r2,r3}
62     vperm   \a3,\a0,\a1,v24 // vcprm(2,3,s2,s3) // {i0,i1,i2,i3}
63 .endm
64
65 .macro FFT4x2 a0, a1, b0, b1, a2, a3, b2, b3
66     vperm   \a2,\a0,\a1,v20 // vcprm(0,1,s2,s1) // {r0,i0,r3,i2}
67     vperm   \a3,\a0,\a1,v21 // vcprm(2,3,s0,s3) // {r1,i1,r2,i3}
68     vperm   \b2,\b0,\b1,v20
69     vperm   \b3,\b0,\b1,v21
70     vaddfp  \a0,\a2,\a3                         // {t1,t2,t6,t5}
71     vsubfp  \a1,\a2,\a3                         // {t3,t4,t8,t7}
72     vaddfp  \b0,\b2,\b3
73     vsubfp  \b1,\b2,\b3
74     vmrghw  \a2,\a0,\a1     // vcprm(0,s0,1,s1) // {t1,t3,t2,t4}
75     vperm   \a3,\a0,\a1,v22 // vcprm(2,s3,3,s2) // {t6,t7,t5,t8}
76     vmrghw  \b2,\b0,\b1
77     vperm   \b3,\b0,\b1,v22
78     vaddfp  \a0,\a2,\a3                         // {r0,r1,i0,i1}
79     vsubfp  \a1,\a2,\a3                         // {r2,r3,i2,i3}
80     vaddfp  \b0,\b2,\b3
81     vsubfp  \b1,\b2,\b3
82     vperm   \a2,\a0,\a1,v23 // vcprm(0,1,s0,s1) // {r0,r1,r2,r3}
83     vperm   \a3,\a0,\a1,v24 // vcprm(2,3,s2,s3) // {i0,i1,i2,i3}
84     vperm   \b2,\b0,\b1,v23
85     vperm   \b3,\b0,\b1,v24
86 .endm
87
88 .macro FFT8 a0, a1, b0, b1, a2, a3, b2, b3, b4 // in,out:a0-b1
89     vmrghw  \b2,\b0,\b1     // vcprm(0,s0,1,s1) // {r4,r6,i4,i6}
90     vmrglw  \b3,\b0,\b1     // vcprm(2,s2,3,s3) // {r5,r7,i5,i7}
91     vperm   \a2,\a0,\a1,v20         // FFT4 ...
92     vperm   \a3,\a0,\a1,v21
93     vaddfp  \b0,\b2,\b3                         // {t1,t3,t2,t4}
94     vsubfp  \b1,\b2,\b3                         // {r5,r7,i5,i7}
95     vperm   \b4,\b1,\b1,v25 // vcprm(2,3,0,1)   // {i5,i7,r5,r7}
96     vaddfp  \a0,\a2,\a3
97     vsubfp  \a1,\a2,\a3
98     vmaddfp \b1,\b1,v17,v14 // * {-1,1,1,-1}/sqrt(2)
99     vmaddfp \b1,\b4,v18,\b1 // * { 1,1,1,1 }/sqrt(2) // {t8,ta,t7,t9}
100     vmrghw  \a2,\a0,\a1
101     vperm   \a3,\a0,\a1,v22
102     vperm   \b2,\b0,\b1,v26 // vcprm(1,2,s3,s0) // {t3,t2,t9,t8}
103     vperm   \b3,\b0,\b1,v27 // vcprm(0,3,s2,s1) // {t1,t4,t7,ta}
104     vaddfp  \a0,\a2,\a3
105     vsubfp  \a1,\a2,\a3
106     vaddfp  \b0,\b2,\b3                         // {t1,t2,t9,ta}
107     vsubfp  \b1,\b2,\b3                         // {t6,t5,tc,tb}
108     vperm   \a2,\a0,\a1,v23
109     vperm   \a3,\a0,\a1,v24
110     vperm   \b2,\b0,\b1,v28 // vcprm(0,2,s1,s3) // {t1,t9,t5,tb}
111     vperm   \b3,\b0,\b1,v29 // vcprm(1,3,s0,s2) // {t2,ta,t6,tc}
112     vsubfp  \b0,\a2,\b2                         // {r4,r5,r6,r7}
113     vsubfp  \b1,\a3,\b3                         // {i4,i5,i6,i7}
114     vaddfp  \a0,\a2,\b2                         // {r0,r1,r2,r3}
115     vaddfp  \a1,\a3,\b3                         // {i0,i1,i2,i3}
116 .endm
117
118 .macro BF d0,d1,s0,s1
119     vsubfp  \d1,\s0,\s1
120     vaddfp  \d0,\s0,\s1
121 .endm
122
123 .macro zip d0,d1,s0,s1
124     vmrghw  \d0,\s0,\s1
125     vmrglw  \d1,\s0,\s1
126 .endm
127
128 .macro def_fft4 interleave
129 fft4\interleave\()_altivec:
130     lvx    v0, 0,r3
131     lvx    v1,r9,r3
132     FFT4   v0,v1,v2,v3
133 .ifnb \interleave
134     zip    v0,v1,v2,v3
135     stvx   v0, 0,r3
136     stvx   v1,r9,r3
137 .else
138     stvx   v2, 0,r3
139     stvx   v3,r9,r3
140 .endif
141     blr
142 .endm
143
144 .macro def_fft8 interleave
145 fft8\interleave\()_altivec:
146     addi   r4,r3,32
147     lvx    v0, 0,r3
148     lvx    v1,r9,r3
149     lvx    v2, 0,r4
150     lvx    v3,r9,r4
151     FFT8   v0,v1,v2,v3,v4,v5,v6,v7,v8
152 .ifnb \interleave
153     zip    v4,v5,v0,v1
154     zip    v6,v7,v2,v3
155     stvx   v4, 0,r3
156     stvx   v5,r9,r3
157     stvx   v6, 0,r4
158     stvx   v7,r9,r4
159 .else
160     stvx   v0, 0,r3
161     stvx   v1,r9,r3
162     stvx   v2, 0,r4
163     stvx   v3,r9,r4
164 .endif
165     blr
166 .endm
167
168 .macro def_fft16 interleave
169 fft16\interleave\()_altivec:
170     addi   r5,r3,64
171     addi   r6,r3,96
172     addi   r4,r3,32
173     lvx    v0, 0,r5
174     lvx    v1,r9,r5
175     lvx    v2, 0,r6
176     lvx    v3,r9,r6
177     FFT4x2 v0,v1,v2,v3,v4,v5,v6,v7
178     lvx    v0, 0,r3
179     lvx    v1,r9,r3
180     lvx    v2, 0,r4
181     lvx    v3,r9,r4
182     FFT8   v0,v1,v2,v3,v8,v9,v10,v11,v12
183     vmaddfp   v8,v4,v15,v14 // r2*wre
184     vmaddfp   v9,v5,v15,v14 // i2*wre
185     vmaddfp  v10,v6,v15,v14 // r3*wre
186     vmaddfp  v11,v7,v15,v14 // i3*wre
187     vmaddfp   v8,v5,v16,v8  // i2*wim
188     vnmsubfp  v9,v4,v16,v9  // r2*wim
189     vnmsubfp v10,v7,v16,v10 // i3*wim
190     vmaddfp  v11,v6,v16,v11 // r3*wim
191     BF     v10,v12,v10,v8
192     BF     v11,v13,v9,v11
193     BF     v0,v4,v0,v10
194     BF     v3,v7,v3,v12
195     BF     v1,v5,v1,v11
196     BF     v2,v6,v2,v13
197 .ifnb \interleave
198     zip     v8, v9,v0,v1
199     zip    v10,v11,v2,v3
200     zip    v12,v13,v4,v5
201     zip    v14,v15,v6,v7
202     stvx    v8, 0,r3
203     stvx    v9,r9,r3
204     stvx   v10, 0,r4
205     stvx   v11,r9,r4
206     stvx   v12, 0,r5
207     stvx   v13,r9,r5
208     stvx   v14, 0,r6
209     stvx   v15,r9,r6
210 .else
211     stvx   v0, 0,r3
212     stvx   v4, 0,r5
213     stvx   v3,r9,r4
214     stvx   v7,r9,r6
215     stvx   v1,r9,r3
216     stvx   v5,r9,r5
217     stvx   v2, 0,r4
218     stvx   v6, 0,r6
219 .endif
220     blr
221 .endm
222
223 // void pass(float *z, float *wre, int n)
224 .macro PASS interleave, suffix
225 fft_pass\suffix\()_altivec:
226     mtctr  r5
227     slwi   r0,r5,4
228     slwi   r7,r5,6   // o2
229     slwi   r5,r5,5   // o1
230     add   r10,r5,r7  // o3
231     add    r0,r4,r0  // wim
232     addi   r6,r5,16  // o1+16
233     addi   r8,r7,16  // o2+16
234     addi  r11,r10,16 // o3+16
235 1:
236     lvx    v8, 0,r4  // wre
237     lvx   v10, 0,r0  // wim
238     sub    r0,r0,r9
239     lvx    v9, 0,r0
240     vperm  v9,v9,v10,v19   // vcprm(s0,3,2,1) => wim[0 .. -3]
241     lvx    v4,r3,r7        // r2 = z[o2]
242     lvx    v5,r3,r8        // i2 = z[o2+16]
243     lvx    v6,r3,r10       // r3 = z[o3]
244     lvx    v7,r3,r11       // i3 = z[o3+16]
245     vmaddfp  v10,v4,v8,v14 // r2*wre
246     vmaddfp  v11,v5,v8,v14 // i2*wre
247     vmaddfp  v12,v6,v8,v14 // r3*wre
248     vmaddfp  v13,v7,v8,v14 // i3*wre
249     lvx    v0, 0,r3        // r0 = z[0]
250     lvx    v3,r3,r6        // i1 = z[o1+16]
251     vmaddfp  v10,v5,v9,v10 // i2*wim
252     vnmsubfp v11,v4,v9,v11 // r2*wim
253     vnmsubfp v12,v7,v9,v12 // i3*wim
254     vmaddfp  v13,v6,v9,v13 // r3*wim
255     lvx    v1,r3,r9        // i0 = z[16]
256     lvx    v2,r3,r5        // r1 = z[o1]
257     BF     v12,v8,v12,v10
258     BF     v13,v9,v11,v13
259     BF     v0,v4,v0,v12
260     BF     v3,v7,v3,v8
261 .if !\interleave
262     stvx   v0, 0,r3
263     stvx   v4,r3,r7
264     stvx   v3,r3,r6
265     stvx   v7,r3,r11
266 .endif
267     BF     v1,v5,v1,v13
268     BF     v2,v6,v2,v9
269 .if !\interleave
270     stvx   v1,r3,r9
271     stvx   v2,r3,r5
272     stvx   v5,r3,r8
273     stvx   v6,r3,r10
274 .else
275     vmrghw v8,v0,v1
276     vmrglw v9,v0,v1
277     stvx   v8, 0,r3
278     stvx   v9,r3,r9
279     vmrghw v8,v2,v3
280     vmrglw v9,v2,v3
281     stvx   v8,r3,r5
282     stvx   v9,r3,r6
283     vmrghw v8,v4,v5
284     vmrglw v9,v4,v5
285     stvx   v8,r3,r7
286     stvx   v9,r3,r8
287     vmrghw v8,v6,v7
288     vmrglw v9,v6,v7
289     stvx   v8,r3,r10
290     stvx   v9,r3,r11
291 .endif
292     addi   r3,r3,32
293     addi   r4,r4,16
294     bdnz 1b
295     sub    r3,r3,r5
296     blr
297 .endm
298
299 #define M_SQRT1_2      0.70710678118654752440  /* 1/sqrt(2) */
300
301 #define WORD_0  0x00,0x01,0x02,0x03
302 #define WORD_1  0x04,0x05,0x06,0x07
303 #define WORD_2  0x08,0x09,0x0a,0x0b
304 #define WORD_3  0x0c,0x0d,0x0e,0x0f
305 #define WORD_s0 0x10,0x11,0x12,0x13
306 #define WORD_s1 0x14,0x15,0x16,0x17
307 #define WORD_s2 0x18,0x19,0x1a,0x1b
308 #define WORD_s3 0x1c,0x1d,0x1e,0x1f
309
310 #define vcprm(a, b, c, d) .byte WORD_##a, WORD_##b, WORD_##c, WORD_##d
311
312     .rodata
313     .align 4
314 fft_data:
315     .float  0, 0, 0, 0
316     .float  1, 0.92387953, M_SQRT1_2, 0.38268343
317     .float  0, 0.38268343, M_SQRT1_2, 0.92387953
318     .float  -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2,-M_SQRT1_2
319     .float   M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2
320     vcprm(s0,3,2,1)
321     vcprm(0,1,s2,s1)
322     vcprm(2,3,s0,s3)
323     vcprm(2,s3,3,s2)
324     vcprm(0,1,s0,s1)
325     vcprm(2,3,s2,s3)
326     vcprm(2,3,0,1)
327     vcprm(1,2,s3,s0)
328     vcprm(0,3,s2,s1)
329     vcprm(0,2,s1,s3)
330     vcprm(1,3,s0,s2)
331
332 .macro lvm  b, r, regs:vararg
333     lvx     \r, 0, \b
334     addi    \b, \b, 16
335   .ifnb \regs
336     lvm     \b, \regs
337   .endif
338 .endm
339
340 .macro stvm b, r, regs:vararg
341     stvx    \r, 0, \b
342     addi    \b, \b, 16
343   .ifnb \regs
344     stvm    \b, \regs
345   .endif
346 .endm
347
348 .macro fft_calc interleave
349 extfunc ff_fft_calc\interleave\()_altivec
350     mflr    r0
351     stp     r0, 2*PS(r1)
352     stpu    r1, -(160+16*PS)(r1)
353     addi    r6, r1, 16*PS
354     stvm    r6, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
355     mfvrsave r0
356     stw     r0, 15*PS(r1)
357     li      r6, 0xfffffffc
358     mtvrsave r6
359
360     movrel  r6, fft_data
361     lvm     r6, v14, v15, v16, v17, v18, v19, v20, v21
362     lvm     r6, v22, v23, v24, v25, v26, v27, v28, v29
363
364     li      r9, 16
365     movrel  r12, X(ff_cos_tabs)
366
367     movrel  r6, fft_dispatch_tab\interleave\()_altivec
368     lwz     r3, 0(r3)
369     subi    r3, r3, 2
370     slwi    r3, r3, 2+ARCH_PPC64
371     lpx     r3, r3, r6
372     mtctr   r3
373     mr      r3, r4
374     bctrl
375
376     addi    r6, r1, 16*PS
377     lvm     r6, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
378     lwz     r6, 15*PS(r1)
379     mtvrsave r6
380     lp      r1, 0(r1)
381     lp      r0, 2*PS(r1)
382     mtlr    r0
383     blr
384 .endm
385
386 .macro DECL_FFT suffix, bits, n, n2, n4
387 fft\n\suffix\()_altivec:
388     mflr  r0
389     stp   r0,PS*(\bits-3)(r1)
390     bl    fft\n2\()_altivec
391     addi2 r3,\n*4
392     bl    fft\n4\()_altivec
393     addi2 r3,\n*2
394     bl    fft\n4\()_altivec
395     addi2 r3,\n*-6
396     lp    r0,PS*(\bits-3)(r1)
397     lp    r4,\bits*PS(r12)
398     mtlr  r0
399     li    r5,\n/16
400     b     fft_pass\suffix\()_altivec
401 .endm
402
403 .macro DECL_FFTS interleave, suffix
404     .text
405     def_fft4  \suffix
406     def_fft8  \suffix
407     def_fft16 \suffix
408     PASS \interleave, \suffix
409     DECL_FFT \suffix, 5,   32,   16,    8
410     DECL_FFT \suffix, 6,   64,   32,   16
411     DECL_FFT \suffix, 7,  128,   64,   32
412     DECL_FFT \suffix, 8,  256,  128,   64
413     DECL_FFT \suffix, 9,  512,  256,  128
414     DECL_FFT \suffix,10, 1024,  512,  256
415     DECL_FFT \suffix,11, 2048, 1024,  512
416     DECL_FFT \suffix,12, 4096, 2048, 1024
417     DECL_FFT \suffix,13, 8192, 4096, 2048
418     DECL_FFT \suffix,14,16384, 8192, 4096
419     DECL_FFT \suffix,15,32768,16384, 8192
420     DECL_FFT \suffix,16,65536,32768,16384
421
422     fft_calc \suffix
423
424     .rodata
425     .align 3
426 fft_dispatch_tab\suffix\()_altivec:
427     PTR fft4\suffix\()_altivec
428     PTR fft8\suffix\()_altivec
429     PTR fft16\suffix\()_altivec
430     PTR fft32\suffix\()_altivec
431     PTR fft64\suffix\()_altivec
432     PTR fft128\suffix\()_altivec
433     PTR fft256\suffix\()_altivec
434     PTR fft512\suffix\()_altivec
435     PTR fft1024\suffix\()_altivec
436     PTR fft2048\suffix\()_altivec
437     PTR fft4096\suffix\()_altivec
438     PTR fft8192\suffix\()_altivec
439     PTR fft16384\suffix\()_altivec
440     PTR fft32768\suffix\()_altivec
441     PTR fft65536\suffix\()_altivec
442 .endm
443
444 DECL_FFTS 0
445 DECL_FFTS 1, _interleave