]> git.sesse.net Git - ffmpeg/blob - libavcodec/x86/fft.asm
DirectDraw Surface image decoder
[ffmpeg] / libavcodec / x86 / fft.asm
1 ;******************************************************************************
2 ;* FFT transform with SSE/3DNow optimizations
3 ;* Copyright (c) 2008 Loren Merritt
4 ;* Copyright (c) 2011 Vitor Sessak
5 ;*
6 ;* This algorithm (though not any of the implementation details) is
7 ;* based on libdjbfft by D. J. Bernstein.
8 ;*
9 ;* This file is part of Libav.
10 ;*
11 ;* Libav is free software; you can redistribute it and/or
12 ;* modify it under the terms of the GNU Lesser General Public
13 ;* License as published by the Free Software Foundation; either
14 ;* version 2.1 of the License, or (at your option) any later version.
15 ;*
16 ;* Libav is distributed in the hope that it will be useful,
17 ;* but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 ;* Lesser General Public License for more details.
20 ;*
21 ;* You should have received a copy of the GNU Lesser General Public
22 ;* License along with Libav; if not, write to the Free Software
23 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 ;******************************************************************************
25
26 ; These functions are not individually interchangeable with the C versions.
27 ; While C takes arrays of FFTComplex, SSE/3DNow leave intermediate results
28 ; in blocks as conventient to the vector size.
29 ; i.e. {4x real, 4x imaginary, 4x real, ...} (or 2x respectively)
30
31 %include "libavutil/x86/x86util.asm"
32
33 %if ARCH_X86_64
34 %define pointer resq
35 %else
36 %define pointer resd
37 %endif
38
39 struc FFTContext
40     .nbits:    resd 1
41     .reverse:  resd 1
42     .revtab:   pointer 1
43     .tmpbuf:   pointer 1
44     .mdctsize: resd 1
45     .mdctbits: resd 1
46     .tcos:     pointer 1
47     .tsin:     pointer 1
48     .fftperm:  pointer 1
49     .fftcalc:  pointer 1
50     .imdctcalc:pointer 1
51     .imdcthalf:pointer 1
52 endstruc
53
54 SECTION_RODATA
55
56 %define M_SQRT1_2 0.70710678118654752440
57 %define M_COS_PI_1_8 0.923879532511287
58 %define M_COS_PI_3_8 0.38268343236509
59
60 align 32
61 ps_cos16_1: dd 1.0, M_COS_PI_1_8, M_SQRT1_2, M_COS_PI_3_8, 1.0, M_COS_PI_1_8, M_SQRT1_2, M_COS_PI_3_8
62 ps_cos16_2: dd 0, M_COS_PI_3_8, M_SQRT1_2, M_COS_PI_1_8, 0, -M_COS_PI_3_8, -M_SQRT1_2, -M_COS_PI_1_8
63
64 ps_root2: times 8 dd M_SQRT1_2
65 ps_root2mppm: dd -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2
66 ps_p1p1m1p1: dd 0, 0, 1<<31, 0, 0, 0, 1<<31, 0
67
68 perm1: dd 0x00, 0x02, 0x03, 0x01, 0x03, 0x00, 0x02, 0x01
69 perm2: dd 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x02, 0x03
70 ps_p1p1m1p1root2: dd 1.0, 1.0, -1.0, 1.0, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2
71 ps_m1m1p1m1p1m1m1m1: dd 1<<31, 1<<31, 0, 1<<31, 0, 1<<31, 1<<31, 1<<31
72 ps_m1m1m1m1: times 4 dd 1<<31
73 ps_m1p1: dd 1<<31, 0
74
75 %assign i 16
76 %rep 13
77 cextern cos_ %+ i
78 %assign i i<<1
79 %endrep
80
81 %if ARCH_X86_64
82     %define pointer dq
83 %else
84     %define pointer dd
85 %endif
86
87 %macro IF0 1+
88 %endmacro
89 %macro IF1 1+
90     %1
91 %endmacro
92
93 SECTION_TEXT
94
95 %macro T2_3DNOW 4 ; z0, z1, mem0, mem1
96     mova     %1, %3
97     mova     %2, %1
98     pfadd    %1, %4
99     pfsub    %2, %4
100 %endmacro
101
102 %macro T4_3DNOW 6 ; z0, z1, z2, z3, tmp0, tmp1
103     mova     %5, %3
104     pfsub    %3, %4
105     pfadd    %5, %4 ; {t6,t5}
106     pxor     %3, [ps_m1p1] ; {t8,t7}
107     mova     %6, %1
108     movd [r0+12], %3
109     punpckhdq %3, [r0+8]
110     pfadd    %1, %5 ; {r0,i0}
111     pfsub    %6, %5 ; {r2,i2}
112     mova     %4, %2
113     pfadd    %2, %3 ; {r1,i1}
114     pfsub    %4, %3 ; {r3,i3}
115     SWAP     %3, %6
116 %endmacro
117
118 ;  in: %1 = {r0,i0,r2,i2,r4,i4,r6,i6}
119 ;      %2 = {r1,i1,r3,i3,r5,i5,r7,i7}
120 ;      %3, %4, %5 tmp
121 ; out: %1 = {r0,r1,r2,r3,i0,i1,i2,i3}
122 ;      %2 = {r4,r5,r6,r7,i4,i5,i6,i7}
123 %macro T8_AVX 5
124     vsubps     %5, %1, %2       ; v  = %1 - %2
125     vaddps     %3, %1, %2       ; w  = %1 + %2
126     vmulps     %2, %5, [ps_p1p1m1p1root2]  ; v *= vals1
127     vpermilps  %2, %2, [perm1]
128     vblendps   %1, %2, %3, 0x33 ; q = {w1,w2,v4,v2,w5,w6,v7,v6}
129     vshufps    %5, %3, %2, 0x4e ; r = {w3,w4,v1,v3,w7,w8,v8,v5}
130     vsubps     %4, %5, %1       ; s = r - q
131     vaddps     %1, %5, %1       ; u = r + q
132     vpermilps  %1, %1, [perm2]  ; k  = {u1,u2,u3,u4,u6,u5,u7,u8}
133     vshufps    %5, %4, %1, 0xbb
134     vshufps    %3, %4, %1, 0xee
135     vperm2f128 %3, %3, %5, 0x13
136     vxorps     %4, %4, [ps_m1m1p1m1p1m1m1m1]  ; s *= {1,1,-1,-1,1,-1,-1,-1}
137     vshufps    %2, %1, %4, 0xdd
138     vshufps    %1, %1, %4, 0x88
139     vperm2f128 %4, %2, %1, 0x02 ; v  = {k1,k3,s1,s3,k2,k4,s2,s4}
140     vperm2f128 %1, %1, %2, 0x13 ; w  = {k6,k8,s6,s8,k5,k7,s5,s7}
141     vsubps     %5, %1, %3
142     vblendps   %1, %5, %1, 0x55 ; w -= {0,s7,0,k7,0,s8,0,k8}
143     vsubps     %2, %4, %1       ; %2 = v - w
144     vaddps     %1, %4, %1       ; %1 = v + w
145 %endmacro
146
147 ; In SSE mode do one fft4 transforms
148 ; in:  %1={r0,i0,r2,i2} %2={r1,i1,r3,i3}
149 ; out: %1={r0,r1,r2,r3} %2={i0,i1,i2,i3}
150 ;
151 ; In AVX mode do two fft4 transforms
152 ; in:  %1={r0,i0,r2,i2,r4,i4,r6,i6} %2={r1,i1,r3,i3,r5,i5,r7,i7}
153 ; out: %1={r0,r1,r2,r3,r4,r5,r6,r7} %2={i0,i1,i2,i3,i4,i5,i6,i7}
154 %macro T4_SSE 3
155     subps    %3, %1, %2       ; {t3,t4,-t8,t7}
156     addps    %1, %1, %2       ; {t1,t2,t6,t5}
157     xorps    %3, %3, [ps_p1p1m1p1]
158     shufps   %2, %1, %3, 0xbe ; {t6,t5,t7,t8}
159     shufps   %1, %1, %3, 0x44 ; {t1,t2,t3,t4}
160     subps    %3, %1, %2       ; {r2,i2,r3,i3}
161     addps    %1, %1, %2       ; {r0,i0,r1,i1}
162     shufps   %2, %1, %3, 0xdd ; {i0,i1,i2,i3}
163     shufps   %1, %1, %3, 0x88 ; {r0,r1,r2,r3}
164 %endmacro
165
166 ; In SSE mode do one FFT8
167 ; in:  %1={r0,r1,r2,r3} %2={i0,i1,i2,i3} %3={r4,i4,r6,i6} %4={r5,i5,r7,i7}
168 ; out: %1={r0,r1,r2,r3} %2={i0,i1,i2,i3} %1={r4,r5,r6,r7} %2={i4,i5,i6,i7}
169 ;
170 ; In AVX mode do two FFT8
171 ; in:  %1={r0,i0,r2,i2,r8, i8, r10,i10} %2={r1,i1,r3,i3,r9, i9, r11,i11}
172 ;      %3={r4,i4,r6,i6,r12,i12,r14,i14} %4={r5,i5,r7,i7,r13,i13,r15,i15}
173 ; out: %1={r0,r1,r2,r3,r8, r9, r10,r11} %2={i0,i1,i2,i3,i8, i9, i10,i11}
174 ;      %3={r4,r5,r6,r7,r12,r13,r14,r15} %4={i4,i5,i6,i7,i12,i13,i14,i15}
175 %macro T8_SSE 6
176     addps    %6, %3, %4       ; {t1,t2,t3,t4}
177     subps    %3, %3, %4       ; {r5,i5,r7,i7}
178     shufps   %4, %3, %3, 0xb1 ; {i5,r5,i7,r7}
179     mulps    %3, %3, [ps_root2mppm] ; {-r5,i5,r7,-i7}
180     mulps    %4, %4, [ps_root2]
181     addps    %3, %3, %4       ; {t8,t7,ta,t9}
182     shufps   %4, %6, %3, 0x9c ; {t1,t4,t7,ta}
183     shufps   %6, %6, %3, 0x36 ; {t3,t2,t9,t8}
184     subps    %3, %6, %4       ; {t6,t5,tc,tb}
185     addps    %6, %6, %4       ; {t1,t2,t9,ta}
186     shufps   %5, %6, %3, 0x8d ; {t2,ta,t6,tc}
187     shufps   %6, %6, %3, 0xd8 ; {t1,t9,t5,tb}
188     subps    %3, %1, %6       ; {r4,r5,r6,r7}
189     addps    %1, %1, %6       ; {r0,r1,r2,r3}
190     subps    %4, %2, %5       ; {i4,i5,i6,i7}
191     addps    %2, %2, %5       ; {i0,i1,i2,i3}
192 %endmacro
193
194 ; scheduled for cpu-bound sizes
195 %macro PASS_SMALL 3 ; (to load m4-m7), wre, wim
196 IF%1 mova    m4, Z(4)
197 IF%1 mova    m5, Z(5)
198     mova     m0, %2 ; wre
199     mova     m1, %3 ; wim
200     mulps    m2, m4, m0 ; r2*wre
201 IF%1 mova    m6, Z2(6)
202     mulps    m3, m5, m1 ; i2*wim
203 IF%1 mova    m7, Z2(7)
204     mulps    m4, m4, m1 ; r2*wim
205     mulps    m5, m5, m0 ; i2*wre
206     addps    m2, m2, m3 ; r2*wre + i2*wim
207     mulps    m3, m1, m7 ; i3*wim
208     subps    m5, m5, m4 ; i2*wre - r2*wim
209     mulps    m1, m1, m6 ; r3*wim
210     mulps    m4, m0, m6 ; r3*wre
211     mulps    m0, m0, m7 ; i3*wre
212     subps    m4, m4, m3 ; r3*wre - i3*wim
213     mova     m3, Z(0)
214     addps    m0, m0, m1 ; i3*wre + r3*wim
215     subps    m1, m4, m2 ; t3
216     addps    m4, m4, m2 ; t5
217     subps    m3, m3, m4 ; r2
218     addps    m4, m4, Z(0) ; r0
219     mova     m6, Z(2)
220     mova   Z(4), m3
221     mova   Z(0), m4
222     subps    m3, m5, m0 ; t4
223     subps    m4, m6, m3 ; r3
224     addps    m3, m3, m6 ; r1
225     mova  Z2(6), m4
226     mova   Z(2), m3
227     mova     m2, Z(3)
228     addps    m3, m5, m0 ; t6
229     subps    m2, m2, m1 ; i3
230     mova     m7, Z(1)
231     addps    m1, m1, Z(3) ; i1
232     mova  Z2(7), m2
233     mova   Z(3), m1
234     subps    m4, m7, m3 ; i2
235     addps    m3, m3, m7 ; i0
236     mova   Z(5), m4
237     mova   Z(1), m3
238 %endmacro
239
240 ; scheduled to avoid store->load aliasing
241 %macro PASS_BIG 1 ; (!interleave)
242     mova     m4, Z(4) ; r2
243     mova     m5, Z(5) ; i2
244     mova     m0, [wq] ; wre
245     mova     m1, [wq+o1q] ; wim
246     mulps    m2, m4, m0 ; r2*wre
247     mova     m6, Z2(6) ; r3
248     mulps    m3, m5, m1 ; i2*wim
249     mova     m7, Z2(7) ; i3
250     mulps    m4, m4, m1 ; r2*wim
251     mulps    m5, m5, m0 ; i2*wre
252     addps    m2, m2, m3 ; r2*wre + i2*wim
253     mulps    m3, m1, m7 ; i3*wim
254     mulps    m1, m1, m6 ; r3*wim
255     subps    m5, m5, m4 ; i2*wre - r2*wim
256     mulps    m4, m0, m6 ; r3*wre
257     mulps    m0, m0, m7 ; i3*wre
258     subps    m4, m4, m3 ; r3*wre - i3*wim
259     mova     m3, Z(0)
260     addps    m0, m0, m1 ; i3*wre + r3*wim
261     subps    m1, m4, m2 ; t3
262     addps    m4, m4, m2 ; t5
263     subps    m3, m3, m4 ; r2
264     addps    m4, m4, Z(0) ; r0
265     mova     m6, Z(2)
266     mova   Z(4), m3
267     mova   Z(0), m4
268     subps    m3, m5, m0 ; t4
269     subps    m4, m6, m3 ; r3
270     addps    m3, m3, m6 ; r1
271 IF%1 mova Z2(6), m4
272 IF%1 mova  Z(2), m3
273     mova     m2, Z(3)
274     addps    m5, m5, m0 ; t6
275     subps    m2, m2, m1 ; i3
276     mova     m7, Z(1)
277     addps    m1, m1, Z(3) ; i1
278 IF%1 mova Z2(7), m2
279 IF%1 mova  Z(3), m1
280     subps    m6, m7, m5 ; i2
281     addps    m5, m5, m7 ; i0
282 IF%1 mova  Z(5), m6
283 IF%1 mova  Z(1), m5
284 %if %1==0
285     INTERL m1, m3, m7, Z, 2
286     INTERL m2, m4, m0, Z2, 6
287
288     mova     m1, Z(0)
289     mova     m2, Z(4)
290
291     INTERL m5, m1, m3, Z, 0
292     INTERL m6, m2, m7, Z, 4
293 %endif
294 %endmacro
295
296 %macro PUNPCK 3
297     mova      %3, %1
298     punpckldq %1, %2
299     punpckhdq %3, %2
300 %endmacro
301
302 %define Z(x) [r0+mmsize*x]
303 %define Z2(x) [r0+mmsize*x]
304 %define ZH(x) [r0+mmsize*x+mmsize/2]
305
306 INIT_YMM avx
307
308 align 16
309 fft8_avx:
310     mova      m0, Z(0)
311     mova      m1, Z(1)
312     T8_AVX    m0, m1, m2, m3, m4
313     mova      Z(0), m0
314     mova      Z(1), m1
315     ret
316
317
318 align 16
319 fft16_avx:
320     mova       m2, Z(2)
321     mova       m3, Z(3)
322     T4_SSE     m2, m3, m7
323
324     mova       m0, Z(0)
325     mova       m1, Z(1)
326     T8_AVX     m0, m1, m4, m5, m7
327
328     mova       m4, [ps_cos16_1]
329     mova       m5, [ps_cos16_2]
330     vmulps     m6, m2, m4
331     vmulps     m7, m3, m5
332     vaddps     m7, m7, m6
333     vmulps     m2, m2, m5
334     vmulps     m3, m3, m4
335     vsubps     m3, m3, m2
336     vblendps   m2, m7, m3, 0xf0
337     vperm2f128 m3, m7, m3, 0x21
338     vaddps     m4, m2, m3
339     vsubps     m2, m3, m2
340     vperm2f128 m2, m2, m2, 0x01
341     vsubps     m3, m1, m2
342     vaddps     m1, m1, m2
343     vsubps     m5, m0, m4
344     vaddps     m0, m0, m4
345     vextractf128   Z(0), m0, 0
346     vextractf128  ZH(0), m1, 0
347     vextractf128   Z(1), m0, 1
348     vextractf128  ZH(1), m1, 1
349     vextractf128   Z(2), m5, 0
350     vextractf128  ZH(2), m3, 0
351     vextractf128   Z(3), m5, 1
352     vextractf128  ZH(3), m3, 1
353     ret
354
355 align 16
356 fft32_avx:
357     call fft16_avx
358
359     mova m0, Z(4)
360     mova m1, Z(5)
361
362     T4_SSE      m0, m1, m4
363
364     mova m2, Z(6)
365     mova m3, Z(7)
366
367     T8_SSE      m0, m1, m2, m3, m4, m6
368     ; m0={r0,r1,r2,r3,r8, r9, r10,r11} m1={i0,i1,i2,i3,i8, i9, i10,i11}
369     ; m2={r4,r5,r6,r7,r12,r13,r14,r15} m3={i4,i5,i6,i7,i12,i13,i14,i15}
370
371     vperm2f128  m4, m0, m2, 0x20
372     vperm2f128  m5, m1, m3, 0x20
373     vperm2f128  m6, m0, m2, 0x31
374     vperm2f128  m7, m1, m3, 0x31
375
376     PASS_SMALL 0, [cos_32], [cos_32+32]
377
378     ret
379
380 fft32_interleave_avx:
381     call fft32_avx
382     mov r2d, 32
383 .deint_loop:
384     mova     m2, Z(0)
385     mova     m3, Z(1)
386     vunpcklps      m0, m2, m3
387     vunpckhps      m1, m2, m3
388     vextractf128   Z(0), m0, 0
389     vextractf128  ZH(0), m1, 0
390     vextractf128   Z(1), m0, 1
391     vextractf128  ZH(1), m1, 1
392     add r0, mmsize*2
393     sub r2d, mmsize/4
394     jg .deint_loop
395     ret
396
397 INIT_XMM sse
398
399 align 16
400 fft4_avx:
401 fft4_sse:
402     mova     m0, Z(0)
403     mova     m1, Z(1)
404     T4_SSE   m0, m1, m2
405     mova   Z(0), m0
406     mova   Z(1), m1
407     ret
408
409 align 16
410 fft8_sse:
411     mova     m0, Z(0)
412     mova     m1, Z(1)
413     T4_SSE   m0, m1, m2
414     mova     m2, Z(2)
415     mova     m3, Z(3)
416     T8_SSE   m0, m1, m2, m3, m4, m5
417     mova   Z(0), m0
418     mova   Z(1), m1
419     mova   Z(2), m2
420     mova   Z(3), m3
421     ret
422
423 align 16
424 fft16_sse:
425     mova     m0, Z(0)
426     mova     m1, Z(1)
427     T4_SSE   m0, m1, m2
428     mova     m2, Z(2)
429     mova     m3, Z(3)
430     T8_SSE   m0, m1, m2, m3, m4, m5
431     mova     m4, Z(4)
432     mova     m5, Z(5)
433     mova   Z(0), m0
434     mova   Z(1), m1
435     mova   Z(2), m2
436     mova   Z(3), m3
437     T4_SSE   m4, m5, m6
438     mova     m6, Z2(6)
439     mova     m7, Z2(7)
440     T4_SSE   m6, m7, m0
441     PASS_SMALL 0, [cos_16], [cos_16+16]
442     ret
443
444
445 %macro FFT48_3DNOW 0
446 align 16
447 fft4 %+ SUFFIX:
448     T2_3DNOW m0, m1, Z(0), Z(1)
449     mova     m2, Z(2)
450     mova     m3, Z(3)
451     T4_3DNOW m0, m1, m2, m3, m4, m5
452     PUNPCK   m0, m1, m4
453     PUNPCK   m2, m3, m5
454     mova   Z(0), m0
455     mova   Z(1), m4
456     mova   Z(2), m2
457     mova   Z(3), m5
458     ret
459
460 align 16
461 fft8 %+ SUFFIX:
462     T2_3DNOW m0, m1, Z(0), Z(1)
463     mova     m2, Z(2)
464     mova     m3, Z(3)
465     T4_3DNOW m0, m1, m2, m3, m4, m5
466     mova   Z(0), m0
467     mova   Z(2), m2
468     T2_3DNOW m4, m5,  Z(4),  Z(5)
469     T2_3DNOW m6, m7, Z2(6), Z2(7)
470     PSWAPD   m0, m5
471     PSWAPD   m2, m7
472     pxor     m0, [ps_m1p1]
473     pxor     m2, [ps_m1p1]
474     pfsub    m5, m0
475     pfadd    m7, m2
476     pfmul    m5, [ps_root2]
477     pfmul    m7, [ps_root2]
478     T4_3DNOW m1, m3, m5, m7, m0, m2
479     mova   Z(5), m5
480     mova  Z2(7), m7
481     mova     m0, Z(0)
482     mova     m2, Z(2)
483     T4_3DNOW m0, m2, m4, m6, m5, m7
484     PUNPCK   m0, m1, m5
485     PUNPCK   m2, m3, m7
486     mova   Z(0), m0
487     mova   Z(1), m5
488     mova   Z(2), m2
489     mova   Z(3), m7
490     PUNPCK   m4,  Z(5), m5
491     PUNPCK   m6, Z2(7), m7
492     mova   Z(4), m4
493     mova   Z(5), m5
494     mova  Z2(6), m6
495     mova  Z2(7), m7
496     ret
497 %endmacro
498
499 %if ARCH_X86_32
500 INIT_MMX 3dnowext
501 FFT48_3DNOW
502
503 INIT_MMX 3dnow
504 FFT48_3DNOW
505 %endif
506
507 %define Z(x) [zcq + o1q*(x&6) + mmsize*(x&1)]
508 %define Z2(x) [zcq + o3q + mmsize*(x&1)]
509 %define ZH(x) [zcq + o1q*(x&6) + mmsize*(x&1) + mmsize/2]
510 %define Z2H(x) [zcq + o3q + mmsize*(x&1) + mmsize/2]
511
512 %macro DECL_PASS 2+ ; name, payload
513 align 16
514 %1:
515 DEFINE_ARGS zc, w, n, o1, o3
516     lea o3q, [nq*3]
517     lea o1q, [nq*8]
518     shl o3q, 4
519 .loop:
520     %2
521     add zcq, mmsize*2
522     add  wq, mmsize
523     sub  nd, mmsize/8
524     jg .loop
525     rep ret
526 %endmacro
527
528 %macro FFT_DISPATCH 2; clobbers 5 GPRs, 8 XMMs
529     lea r2, [dispatch_tab%1]
530     mov r2, [r2 + (%2q-2)*gprsize]
531 %ifdef PIC
532     lea r3, [$$]
533     add r2, r3
534 %endif
535     call r2
536 %endmacro ; FFT_DISPATCH
537
538 INIT_YMM avx
539
540 %macro INTERL_AVX 5
541     vunpckhps      %3, %2, %1
542     vunpcklps      %2, %2, %1
543     vextractf128   %4(%5), %2, 0
544     vextractf128  %4 %+ H(%5), %3, 0
545     vextractf128   %4(%5 + 1), %2, 1
546     vextractf128  %4 %+ H(%5 + 1), %3, 1
547 %endmacro
548
549 %define INTERL INTERL_AVX
550
551 DECL_PASS pass_avx, PASS_BIG 1
552 DECL_PASS pass_interleave_avx, PASS_BIG 0
553
554 cglobal fft_calc, 2,5,8
555     mov     r3d, [r0 + FFTContext.nbits]
556     mov     r0, r1
557     mov     r1, r3
558     FFT_DISPATCH _interleave %+ SUFFIX, r1
559     REP_RET
560
561
562 INIT_XMM sse
563
564 %macro INTERL_SSE 5
565     mova     %3, %2
566     unpcklps %2, %1
567     unpckhps %3, %1
568     mova  %4(%5), %2
569     mova  %4(%5+1), %3
570 %endmacro
571
572 %define INTERL INTERL_SSE
573
574 DECL_PASS pass_sse, PASS_BIG 1
575 DECL_PASS pass_interleave_sse, PASS_BIG 0
576
577 %macro FFT_CALC_FUNC 0
578 cglobal fft_calc, 2,5,8
579     mov     r3d, [r0 + FFTContext.nbits]
580     PUSH    r1
581     PUSH    r3
582     mov     r0, r1
583     mov     r1, r3
584     FFT_DISPATCH _interleave %+ SUFFIX, r1
585     POP     rcx
586     POP     r4
587     cmp     rcx, 3+(mmsize/16)
588     jg      .end
589     mov     r2, -1
590     add     rcx, 3
591     shl     r2, cl
592     sub     r4, r2
593 .loop:
594 %if mmsize == 8
595     PSWAPD  m0, [r4 + r2 + 4]
596     mova [r4 + r2 + 4], m0
597 %else
598     movaps   xmm0, [r4 + r2]
599     movaps   xmm1, xmm0
600     unpcklps xmm0, [r4 + r2 + 16]
601     unpckhps xmm1, [r4 + r2 + 16]
602     movaps   [r4 + r2],      xmm0
603     movaps   [r4 + r2 + 16], xmm1
604 %endif
605     add      r2, mmsize*2
606     jl       .loop
607 .end:
608 %if cpuflag(3dnow)
609     femms
610     RET
611 %else
612     REP_RET
613 %endif
614 %endmacro
615
616 %if ARCH_X86_32
617 INIT_MMX 3dnow
618 FFT_CALC_FUNC
619 INIT_MMX 3dnowext
620 FFT_CALC_FUNC
621 %endif
622 INIT_XMM sse
623 FFT_CALC_FUNC
624
625 cglobal fft_permute, 2,7,1
626     mov     r4,  [r0 + FFTContext.revtab]
627     mov     r5,  [r0 + FFTContext.tmpbuf]
628     mov     ecx, [r0 + FFTContext.nbits]
629     mov     r2, 1
630     shl     r2, cl
631     xor     r0, r0
632 %if ARCH_X86_32
633     mov     r1, r1m
634 %endif
635 .loop:
636     movaps  xmm0, [r1 + 8*r0]
637     movzx   r6, word [r4 + 2*r0]
638     movzx   r3, word [r4 + 2*r0 + 2]
639     movlps  [r5 + 8*r6], xmm0
640     movhps  [r5 + 8*r3], xmm0
641     add     r0, 2
642     cmp     r0, r2
643     jl      .loop
644     shl     r2, 3
645     add     r1, r2
646     add     r5, r2
647     neg     r2
648 ; nbits >= 2 (FFT4) and sizeof(FFTComplex)=8 => at least 32B
649 .loopcopy:
650     movaps  xmm0, [r5 + r2]
651     movaps  xmm1, [r5 + r2 + 16]
652     movaps  [r1 + r2], xmm0
653     movaps  [r1 + r2 + 16], xmm1
654     add     r2, 32
655     jl      .loopcopy
656     REP_RET
657
658 %macro IMDCT_CALC_FUNC 0
659 cglobal imdct_calc, 3,5,3
660     mov     r3d, [r0 + FFTContext.mdctsize]
661     mov     r4,  [r0 + FFTContext.imdcthalf]
662     add     r1,  r3
663     PUSH    r3
664     PUSH    r1
665 %if ARCH_X86_32
666     push    r2
667     push    r1
668     push    r0
669 %else
670     sub     rsp, 8+32*WIN64 ; allocate win64 shadow space
671 %endif
672     call    r4
673 %if ARCH_X86_32
674     add     esp, 12
675 %else
676     add     rsp, 8+32*WIN64
677 %endif
678     POP     r1
679     POP     r3
680     lea     r0, [r1 + 2*r3]
681     mov     r2, r3
682     sub     r3, mmsize
683     neg     r2
684     mova    m2, [ps_m1m1m1m1]
685 .loop:
686 %if mmsize == 8
687     PSWAPD  m0, [r1 + r3]
688     PSWAPD  m1, [r0 + r2]
689     pxor    m0, m2
690 %else
691     mova    m0, [r1 + r3]
692     mova    m1, [r0 + r2]
693     shufps  m0, m0, 0x1b
694     shufps  m1, m1, 0x1b
695     xorps   m0, m2
696 %endif
697     mova [r0 + r3], m1
698     mova [r1 + r2], m0
699     sub     r3, mmsize
700     add     r2, mmsize
701     jl      .loop
702 %if cpuflag(3dnow)
703     femms
704     RET
705 %else
706     REP_RET
707 %endif
708 %endmacro
709
710 %if ARCH_X86_32
711 INIT_MMX 3dnow
712 IMDCT_CALC_FUNC
713 INIT_MMX 3dnowext
714 IMDCT_CALC_FUNC
715 %endif
716
717 INIT_XMM sse
718 IMDCT_CALC_FUNC
719
720 %if ARCH_X86_32
721 INIT_MMX 3dnow
722 %define mulps pfmul
723 %define addps pfadd
724 %define subps pfsub
725 %define unpcklps punpckldq
726 %define unpckhps punpckhdq
727 DECL_PASS pass_3dnow, PASS_SMALL 1, [wq], [wq+o1q]
728 DECL_PASS pass_interleave_3dnow, PASS_BIG 0
729 %define pass_3dnowext pass_3dnow
730 %define pass_interleave_3dnowext pass_interleave_3dnow
731 %endif
732
733 %ifdef PIC
734 %define SECTION_REL - $$
735 %else
736 %define SECTION_REL
737 %endif
738
739 %macro DECL_FFT 1-2 ; nbits, suffix
740 %ifidn %0, 1
741 %xdefine fullsuffix SUFFIX
742 %else
743 %xdefine fullsuffix %2 %+ SUFFIX
744 %endif
745 %xdefine list_of_fft fft4 %+ SUFFIX SECTION_REL, fft8 %+ SUFFIX SECTION_REL
746 %if %1>=5
747 %xdefine list_of_fft list_of_fft, fft16 %+ SUFFIX SECTION_REL
748 %endif
749 %if %1>=6
750 %xdefine list_of_fft list_of_fft, fft32 %+ fullsuffix SECTION_REL
751 %endif
752
753 %assign n 1<<%1
754 %rep 17-%1
755 %assign n2 n/2
756 %assign n4 n/4
757 %xdefine list_of_fft list_of_fft, fft %+ n %+ fullsuffix SECTION_REL
758
759 align 16
760 fft %+ n %+ fullsuffix:
761     call fft %+ n2 %+ SUFFIX
762     add r0, n*4 - (n&(-2<<%1))
763     call fft %+ n4 %+ SUFFIX
764     add r0, n*2 - (n2&(-2<<%1))
765     call fft %+ n4 %+ SUFFIX
766     sub r0, n*6 + (n2&(-2<<%1))
767     lea r1, [cos_ %+ n]
768     mov r2d, n4/2
769     jmp pass %+ fullsuffix
770
771 %assign n n*2
772 %endrep
773 %undef n
774
775 align 8
776 dispatch_tab %+ fullsuffix: pointer list_of_fft
777 %endmacro ; DECL_FFT
778
779 INIT_YMM avx
780 DECL_FFT 6
781 DECL_FFT 6, _interleave
782 INIT_XMM sse
783 DECL_FFT 5
784 DECL_FFT 5, _interleave
785 %if ARCH_X86_32
786 INIT_MMX 3dnow
787 DECL_FFT 4
788 DECL_FFT 4, _interleave
789 INIT_MMX 3dnowext
790 DECL_FFT 4
791 DECL_FFT 4, _interleave
792 %endif
793
794 INIT_XMM sse
795 %undef mulps
796 %undef addps
797 %undef subps
798 %undef unpcklps
799 %undef unpckhps
800
801 %macro PREROTATER 5 ;-2*k, 2*k, input+n4, tcos+n8, tsin+n8
802 %if mmsize == 8 ; j*2+2-n4, n4-2-j*2, input+n4, tcos+n8, tsin+n8
803     PSWAPD     m0, [%3+%2*4]
804     movq       m2, [%3+%1*4-8]
805     movq       m3, m0
806     punpckldq  m0, m2
807     punpckhdq  m2, m3
808     movd       m1, [%4+%1*2-4] ; tcos[j]
809     movd       m3, [%4+%2*2]   ; tcos[n4-j-1]
810     punpckldq  m1, [%5+%1*2-4] ; tsin[j]
811     punpckldq  m3, [%5+%2*2]   ; tsin[n4-j-1]
812
813     mova       m4, m0
814     PSWAPD     m5, m1
815     pfmul      m0, m1
816     pfmul      m4, m5
817     mova       m6, m2
818     PSWAPD     m5, m3
819     pfmul      m2, m3
820     pfmul      m6, m5
821 %if cpuflag(3dnowext)
822     pfpnacc    m0, m4
823     pfpnacc    m2, m6
824 %else
825     SBUTTERFLY dq, 0, 4, 1
826     SBUTTERFLY dq, 2, 6, 3
827     pxor       m4, m7
828     pxor       m6, m7
829     pfadd      m0, m4
830     pfadd      m2, m6
831 %endif
832 %else
833     movaps   xmm0, [%3+%2*4]
834     movaps   xmm1, [%3+%1*4-0x10]
835     movaps   xmm2, xmm0
836     shufps   xmm0, xmm1, 0x88
837     shufps   xmm1, xmm2, 0x77
838     movlps   xmm4, [%4+%2*2]
839     movlps   xmm5, [%5+%2*2+0x0]
840     movhps   xmm4, [%4+%1*2-0x8]
841     movhps   xmm5, [%5+%1*2-0x8]
842     movaps   xmm2, xmm0
843     movaps   xmm3, xmm1
844     mulps    xmm0, xmm5
845     mulps    xmm1, xmm4
846     mulps    xmm2, xmm4
847     mulps    xmm3, xmm5
848     subps    xmm1, xmm0
849     addps    xmm2, xmm3
850     movaps   xmm0, xmm1
851     unpcklps xmm1, xmm2
852     unpckhps xmm0, xmm2
853 %endif
854 %endmacro
855
856 %macro CMUL 6 ;j, xmm0, xmm1, 3, 4, 5
857     mulps      m6, %3, [%5+%1]
858     mulps      m7, %2, [%5+%1]
859     mulps      %2, %2, [%6+%1]
860     mulps      %3, %3, [%6+%1]
861     subps      %2, %2, m6
862     addps      %3, %3, m7
863 %endmacro
864
865 %macro POSROTATESHUF_AVX 5 ;j, k, z+n8, tcos+n8, tsin+n8
866 .post:
867     vmovaps      ymm1,   [%3+%1*2]
868     vmovaps      ymm0,   [%3+%1*2+0x20]
869     vmovaps      ymm3,   [%3+%2*2]
870     vmovaps      ymm2,   [%3+%2*2+0x20]
871
872     CMUL         %1, ymm0, ymm1, %3, %4, %5
873     CMUL         %2, ymm2, ymm3, %3, %4, %5
874     vshufps      ymm1, ymm1, ymm1, 0x1b
875     vshufps      ymm3, ymm3, ymm3, 0x1b
876     vperm2f128   ymm1, ymm1, ymm1, 0x01
877     vperm2f128   ymm3, ymm3, ymm3, 0x01
878     vunpcklps    ymm6, ymm2, ymm1
879     vunpckhps    ymm4, ymm2, ymm1
880     vunpcklps    ymm7, ymm0, ymm3
881     vunpckhps    ymm5, ymm0, ymm3
882
883     vextractf128 [%3+%1*2],      ymm7, 0
884     vextractf128 [%3+%1*2+0x10], ymm5, 0
885     vextractf128 [%3+%1*2+0x20], ymm7, 1
886     vextractf128 [%3+%1*2+0x30], ymm5, 1
887
888     vextractf128 [%3+%2*2],      ymm6, 0
889     vextractf128 [%3+%2*2+0x10], ymm4, 0
890     vextractf128 [%3+%2*2+0x20], ymm6, 1
891     vextractf128 [%3+%2*2+0x30], ymm4, 1
892     sub      %2,   0x20
893     add      %1,   0x20
894     jl       .post
895 %endmacro
896
897 %macro POSROTATESHUF 5 ;j, k, z+n8, tcos+n8, tsin+n8
898 .post:
899     movaps   xmm1, [%3+%1*2]
900     movaps   xmm0, [%3+%1*2+0x10]
901     CMUL     %1,   xmm0, xmm1, %3, %4, %5
902     movaps   xmm5, [%3+%2*2]
903     movaps   xmm4, [%3+%2*2+0x10]
904     CMUL     %2,   xmm4, xmm5, %3, %4, %5
905     shufps   xmm1, xmm1, 0x1b
906     shufps   xmm5, xmm5, 0x1b
907     movaps   xmm6, xmm4
908     unpckhps xmm4, xmm1
909     unpcklps xmm6, xmm1
910     movaps   xmm2, xmm0
911     unpcklps xmm0, xmm5
912     unpckhps xmm2, xmm5
913     movaps   [%3+%2*2],      xmm6
914     movaps   [%3+%2*2+0x10], xmm4
915     movaps   [%3+%1*2],      xmm0
916     movaps   [%3+%1*2+0x10], xmm2
917     sub      %2,   0x10
918     add      %1,   0x10
919     jl       .post
920 %endmacro
921
922 %macro CMUL_3DNOW 6
923     mova       m6, [%1+%2*2]
924     mova       %3, [%1+%2*2+8]
925     mova       %4, m6
926     mova       m7, %3
927     pfmul      m6, [%5+%2]
928     pfmul      %3, [%6+%2]
929     pfmul      %4, [%6+%2]
930     pfmul      m7, [%5+%2]
931     pfsub      %3, m6
932     pfadd      %4, m7
933 %endmacro
934
935 %macro POSROTATESHUF_3DNOW 5 ;j, k, z+n8, tcos+n8, tsin+n8
936 .post:
937     CMUL_3DNOW %3, %1, m0, m1, %4, %5
938     CMUL_3DNOW %3, %2, m2, m3, %4, %5
939     movd  [%3+%1*2+ 0], m0
940     movd  [%3+%2*2+12], m1
941     movd  [%3+%2*2+ 0], m2
942     movd  [%3+%1*2+12], m3
943     psrlq      m0, 32
944     psrlq      m1, 32
945     psrlq      m2, 32
946     psrlq      m3, 32
947     movd  [%3+%1*2+ 8], m0
948     movd  [%3+%2*2+ 4], m1
949     movd  [%3+%2*2+ 8], m2
950     movd  [%3+%1*2+ 4], m3
951     sub        %2, 8
952     add        %1, 8
953     jl         .post
954 %endmacro
955
956 %macro DECL_IMDCT 1
957 cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *input
958 %if ARCH_X86_64
959 %define rrevtab r7
960 %define rtcos   r8
961 %define rtsin   r9
962 %else
963 %define rrevtab r6
964 %define rtsin   r6
965 %define rtcos   r5
966 %endif
967     mov   r3d, [r0+FFTContext.mdctsize]
968     add   r2, r3
969     shr   r3, 1
970     mov   rtcos, [r0+FFTContext.tcos]
971     mov   rtsin, [r0+FFTContext.tsin]
972     add   rtcos, r3
973     add   rtsin, r3
974 %if ARCH_X86_64 == 0
975     push  rtcos
976     push  rtsin
977 %endif
978     shr   r3, 1
979     mov   rrevtab, [r0+FFTContext.revtab]
980     add   rrevtab, r3
981 %if ARCH_X86_64 == 0
982     push  rrevtab
983 %endif
984
985 %if mmsize == 8
986     sub   r3, 2
987 %else
988     sub   r3, 4
989 %endif
990 %if ARCH_X86_64 || mmsize == 8
991     xor   r4, r4
992     sub   r4, r3
993 %endif
994 %if notcpuflag(3dnowext) && mmsize == 8
995     movd  m7, [ps_m1m1m1m1]
996 %endif
997 .pre:
998 %if ARCH_X86_64 == 0
999 ;unspill
1000 %if mmsize != 8
1001     xor   r4, r4
1002     sub   r4, r3
1003 %endif
1004     mov   rtcos, [esp+8]
1005     mov   rtsin, [esp+4]
1006 %endif
1007
1008     PREROTATER r4, r3, r2, rtcos, rtsin
1009 %if mmsize == 8
1010     mov    r6, [esp]                ; rrevtab = ptr+n8
1011     movzx  r5,  word [rrevtab+r4-2] ; rrevtab[j]
1012     movzx  r6,  word [rrevtab+r3]   ; rrevtab[n4-j-1]
1013     mova [r1+r5*8], m0
1014     mova [r1+r6*8], m2
1015     add    r4, 2
1016     sub    r3, 2
1017 %else
1018 %if ARCH_X86_64
1019     movzx  r5,  word [rrevtab+r4-4]
1020     movzx  r6,  word [rrevtab+r4-2]
1021     movzx  r10, word [rrevtab+r3]
1022     movzx  r11, word [rrevtab+r3+2]
1023     movlps [r1+r5 *8], xmm0
1024     movhps [r1+r6 *8], xmm0
1025     movlps [r1+r10*8], xmm1
1026     movhps [r1+r11*8], xmm1
1027     add    r4, 4
1028 %else
1029     mov    r6, [esp]
1030     movzx  r5, word [r6+r4-4]
1031     movzx  r4, word [r6+r4-2]
1032     movlps [r1+r5*8], xmm0
1033     movhps [r1+r4*8], xmm0
1034     movzx  r5, word [r6+r3]
1035     movzx  r4, word [r6+r3+2]
1036     movlps [r1+r5*8], xmm1
1037     movhps [r1+r4*8], xmm1
1038 %endif
1039     sub    r3, 4
1040 %endif
1041     jns    .pre
1042
1043     mov  r5, r0
1044     mov  r6, r1
1045     mov  r0, r1
1046     mov  r1d, [r5+FFTContext.nbits]
1047
1048     FFT_DISPATCH SUFFIX, r1
1049
1050     mov  r0d, [r5+FFTContext.mdctsize]
1051     add  r6, r0
1052     shr  r0, 1
1053 %if ARCH_X86_64 == 0
1054 %define rtcos r2
1055 %define rtsin r3
1056     mov  rtcos, [esp+8]
1057     mov  rtsin, [esp+4]
1058 %endif
1059     neg  r0
1060     mov  r1, -mmsize
1061     sub  r1, r0
1062     %1 r0, r1, r6, rtcos, rtsin
1063 %if ARCH_X86_64 == 0
1064     add esp, 12
1065 %endif
1066 %if mmsize == 8
1067     femms
1068 %endif
1069     RET
1070 %endmacro
1071
1072 DECL_IMDCT POSROTATESHUF
1073
1074 %if ARCH_X86_32
1075 INIT_MMX 3dnow
1076 DECL_IMDCT POSROTATESHUF_3DNOW
1077
1078 INIT_MMX 3dnowext
1079 DECL_IMDCT POSROTATESHUF_3DNOW
1080 %endif
1081
1082 INIT_YMM avx
1083 DECL_IMDCT POSROTATESHUF_AVX