x86: Refactor PSWAPD fallback implementations and port to cpuflags
[ffmpeg.git] / 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 %if HAVE_AVX_EXTERNAL
309 align 16
310 fft8_avx:
311     mova      m0, Z(0)
312     mova      m1, Z(1)
313     T8_AVX    m0, m1, m2, m3, m4
314     mova      Z(0), m0
315     mova      Z(1), m1
316     ret
317
318
319 align 16
320 fft16_avx:
321     mova       m2, Z(2)
322     mova       m3, Z(3)
323     T4_SSE     m2, m3, m7
324
325     mova       m0, Z(0)
326     mova       m1, Z(1)
327     T8_AVX     m0, m1, m4, m5, m7
328
329     mova       m4, [ps_cos16_1]
330     mova       m5, [ps_cos16_2]
331     vmulps     m6, m2, m4
332     vmulps     m7, m3, m5
333     vaddps     m7, m7, m6
334     vmulps     m2, m2, m5
335     vmulps     m3, m3, m4
336     vsubps     m3, m3, m2
337     vblendps   m2, m7, m3, 0xf0
338     vperm2f128 m3, m7, m3, 0x21
339     vaddps     m4, m2, m3
340     vsubps     m2, m3, m2
341     vperm2f128 m2, m2, m2, 0x01
342     vsubps     m3, m1, m2
343     vaddps     m1, m1, m2
344     vsubps     m5, m0, m4
345     vaddps     m0, m0, m4
346     vextractf128   Z(0), m0, 0
347     vextractf128  ZH(0), m1, 0
348     vextractf128   Z(1), m0, 1
349     vextractf128  ZH(1), m1, 1
350     vextractf128   Z(2), m5, 0
351     vextractf128  ZH(2), m3, 0
352     vextractf128   Z(3), m5, 1
353     vextractf128  ZH(3), m3, 1
354     ret
355
356 align 16
357 fft32_avx:
358     call fft16_avx
359
360     mova m0, Z(4)
361     mova m1, Z(5)
362
363     T4_SSE      m0, m1, m4
364
365     mova m2, Z(6)
366     mova m3, Z(7)
367
368     T8_SSE      m0, m1, m2, m3, m4, m6
369     ; m0={r0,r1,r2,r3,r8, r9, r10,r11} m1={i0,i1,i2,i3,i8, i9, i10,i11}
370     ; m2={r4,r5,r6,r7,r12,r13,r14,r15} m3={i4,i5,i6,i7,i12,i13,i14,i15}
371
372     vperm2f128  m4, m0, m2, 0x20
373     vperm2f128  m5, m1, m3, 0x20
374     vperm2f128  m6, m0, m2, 0x31
375     vperm2f128  m7, m1, m3, 0x31
376
377     PASS_SMALL 0, [cos_32], [cos_32+32]
378
379     ret
380
381 fft32_interleave_avx:
382     call fft32_avx
383     mov r2d, 32
384 .deint_loop:
385     mova     m2, Z(0)
386     mova     m3, Z(1)
387     vunpcklps      m0, m2, m3
388     vunpckhps      m1, m2, m3
389     vextractf128   Z(0), m0, 0
390     vextractf128  ZH(0), m1, 0
391     vextractf128   Z(1), m0, 1
392     vextractf128  ZH(1), m1, 1
393     add r0, mmsize*2
394     sub r2d, mmsize/4
395     jg .deint_loop
396     ret
397 %endif
398
399 INIT_XMM sse
400
401 align 16
402 fft4_avx:
403 fft4_sse:
404     mova     m0, Z(0)
405     mova     m1, Z(1)
406     T4_SSE   m0, m1, m2
407     mova   Z(0), m0
408     mova   Z(1), m1
409     ret
410
411 align 16
412 fft8_sse:
413     mova     m0, Z(0)
414     mova     m1, Z(1)
415     T4_SSE   m0, m1, m2
416     mova     m2, Z(2)
417     mova     m3, Z(3)
418     T8_SSE   m0, m1, m2, m3, m4, m5
419     mova   Z(0), m0
420     mova   Z(1), m1
421     mova   Z(2), m2
422     mova   Z(3), m3
423     ret
424
425 align 16
426 fft16_sse:
427     mova     m0, Z(0)
428     mova     m1, Z(1)
429     T4_SSE   m0, m1, m2
430     mova     m2, Z(2)
431     mova     m3, Z(3)
432     T8_SSE   m0, m1, m2, m3, m4, m5
433     mova     m4, Z(4)
434     mova     m5, Z(5)
435     mova   Z(0), m0
436     mova   Z(1), m1
437     mova   Z(2), m2
438     mova   Z(3), m3
439     T4_SSE   m4, m5, m6
440     mova     m6, Z2(6)
441     mova     m7, Z2(7)
442     T4_SSE   m6, m7, m0
443     PASS_SMALL 0, [cos_16], [cos_16+16]
444     ret
445
446
447 %macro FFT48_3DNOW 0
448 align 16
449 fft4 %+ SUFFIX:
450     T2_3DNOW m0, m1, Z(0), Z(1)
451     mova     m2, Z(2)
452     mova     m3, Z(3)
453     T4_3DNOW m0, m1, m2, m3, m4, m5
454     PUNPCK   m0, m1, m4
455     PUNPCK   m2, m3, m5
456     mova   Z(0), m0
457     mova   Z(1), m4
458     mova   Z(2), m2
459     mova   Z(3), m5
460     ret
461
462 align 16
463 fft8 %+ SUFFIX:
464     T2_3DNOW m0, m1, Z(0), Z(1)
465     mova     m2, Z(2)
466     mova     m3, Z(3)
467     T4_3DNOW m0, m1, m2, m3, m4, m5
468     mova   Z(0), m0
469     mova   Z(2), m2
470     T2_3DNOW m4, m5,  Z(4),  Z(5)
471     T2_3DNOW m6, m7, Z2(6), Z2(7)
472     PSWAPD   m0, m5
473     PSWAPD   m2, m7
474     pxor     m0, [ps_m1p1]
475     pxor     m2, [ps_m1p1]
476     pfsub    m5, m0
477     pfadd    m7, m2
478     pfmul    m5, [ps_root2]
479     pfmul    m7, [ps_root2]
480     T4_3DNOW m1, m3, m5, m7, m0, m2
481     mova   Z(5), m5
482     mova  Z2(7), m7
483     mova     m0, Z(0)
484     mova     m2, Z(2)
485     T4_3DNOW m0, m2, m4, m6, m5, m7
486     PUNPCK   m0, m1, m5
487     PUNPCK   m2, m3, m7
488     mova   Z(0), m0
489     mova   Z(1), m5
490     mova   Z(2), m2
491     mova   Z(3), m7
492     PUNPCK   m4,  Z(5), m5
493     PUNPCK   m6, Z2(7), m7
494     mova   Z(4), m4
495     mova   Z(5), m5
496     mova  Z2(6), m6
497     mova  Z2(7), m7
498     ret
499 %endmacro
500
501 %if ARCH_X86_32
502 INIT_MMX 3dnowext
503 FFT48_3DNOW
504
505 INIT_MMX 3dnow
506 FFT48_3DNOW
507 %endif
508
509 %define Z(x) [zcq + o1q*(x&6) + mmsize*(x&1)]
510 %define Z2(x) [zcq + o3q + mmsize*(x&1)]
511 %define ZH(x) [zcq + o1q*(x&6) + mmsize*(x&1) + mmsize/2]
512 %define Z2H(x) [zcq + o3q + mmsize*(x&1) + mmsize/2]
513
514 %macro DECL_PASS 2+ ; name, payload
515 align 16
516 %1:
517 DEFINE_ARGS zc, w, n, o1, o3
518     lea o3q, [nq*3]
519     lea o1q, [nq*8]
520     shl o3q, 4
521 .loop:
522     %2
523     add zcq, mmsize*2
524     add  wq, mmsize
525     sub  nd, mmsize/8
526     jg .loop
527     rep ret
528 %endmacro
529
530 %macro FFT_DISPATCH 2; clobbers 5 GPRs, 8 XMMs
531     lea r2, [dispatch_tab%1]
532     mov r2, [r2 + (%2q-2)*gprsize]
533 %ifdef PIC
534     lea r3, [$$]
535     add r2, r3
536 %endif
537     call r2
538 %endmacro ; FFT_DISPATCH
539
540 INIT_YMM avx
541
542 %if HAVE_AVX_EXTERNAL
543 %macro INTERL_AVX 5
544     vunpckhps      %3, %2, %1
545     vunpcklps      %2, %2, %1
546     vextractf128   %4(%5), %2, 0
547     vextractf128  %4 %+ H(%5), %3, 0
548     vextractf128   %4(%5 + 1), %2, 1
549     vextractf128  %4 %+ H(%5 + 1), %3, 1
550 %endmacro
551
552 %define INTERL INTERL_AVX
553
554 DECL_PASS pass_avx, PASS_BIG 1
555 DECL_PASS pass_interleave_avx, PASS_BIG 0
556
557 cglobal fft_calc, 2,5,8
558     mov     r3d, [r0 + FFTContext.nbits]
559     mov     r0, r1
560     mov     r1, r3
561     FFT_DISPATCH _interleave %+ SUFFIX, r1
562     REP_RET
563
564 %endif
565
566 INIT_XMM sse
567
568 %macro INTERL_SSE 5
569     mova     %3, %2
570     unpcklps %2, %1
571     unpckhps %3, %1
572     mova  %4(%5), %2
573     mova  %4(%5+1), %3
574 %endmacro
575
576 %define INTERL INTERL_SSE
577
578 DECL_PASS pass_sse, PASS_BIG 1
579 DECL_PASS pass_interleave_sse, PASS_BIG 0
580
581 %macro FFT_CALC_FUNC 0
582 cglobal fft_calc, 2,5,8
583     mov     r3d, [r0 + FFTContext.nbits]
584     PUSH    r1
585     PUSH    r3
586     mov     r0, r1
587     mov     r1, r3
588     FFT_DISPATCH _interleave %+ SUFFIX, r1
589     POP     rcx
590     POP     r4
591     cmp     rcx, 3+(mmsize/16)
592     jg      .end
593     mov     r2, -1
594     add     rcx, 3
595     shl     r2, cl
596     sub     r4, r2
597 .loop:
598 %if mmsize == 8
599     PSWAPD  m0, [r4 + r2 + 4]
600     mova [r4 + r2 + 4], m0
601 %else
602     movaps   xmm0, [r4 + r2]
603     movaps   xmm1, xmm0
604     unpcklps xmm0, [r4 + r2 + 16]
605     unpckhps xmm1, [r4 + r2 + 16]
606     movaps   [r4 + r2],      xmm0
607     movaps   [r4 + r2 + 16], xmm1
608 %endif
609     add      r2, mmsize*2
610     jl       .loop
611 .end:
612 %if cpuflag(3dnow)
613     femms
614     RET
615 %else
616     REP_RET
617 %endif
618 %endmacro
619
620 %if ARCH_X86_32
621 INIT_MMX 3dnow
622 FFT_CALC_FUNC
623 INIT_MMX 3dnowext
624 FFT_CALC_FUNC
625 %endif
626 INIT_XMM sse
627 FFT_CALC_FUNC
628
629 cglobal fft_permute, 2,7,1
630     mov     r4,  [r0 + FFTContext.revtab]
631     mov     r5,  [r0 + FFTContext.tmpbuf]
632     mov     ecx, [r0 + FFTContext.nbits]
633     mov     r2, 1
634     shl     r2, cl
635     xor     r0, r0
636 %if ARCH_X86_32
637     mov     r1, r1m
638 %endif
639 .loop:
640     movaps  xmm0, [r1 + 8*r0]
641     movzx   r6, word [r4 + 2*r0]
642     movzx   r3, word [r4 + 2*r0 + 2]
643     movlps  [r5 + 8*r6], xmm0
644     movhps  [r5 + 8*r3], xmm0
645     add     r0, 2
646     cmp     r0, r2
647     jl      .loop
648     shl     r2, 3
649     add     r1, r2
650     add     r5, r2
651     neg     r2
652 ; nbits >= 2 (FFT4) and sizeof(FFTComplex)=8 => at least 32B
653 .loopcopy:
654     movaps  xmm0, [r5 + r2]
655     movaps  xmm1, [r5 + r2 + 16]
656     movaps  [r1 + r2], xmm0
657     movaps  [r1 + r2 + 16], xmm1
658     add     r2, 32
659     jl      .loopcopy
660     REP_RET
661
662 %macro IMDCT_CALC_FUNC 0
663 cglobal imdct_calc, 3,5,3
664     mov     r3d, [r0 + FFTContext.mdctsize]
665     mov     r4,  [r0 + FFTContext.imdcthalf]
666     add     r1,  r3
667     PUSH    r3
668     PUSH    r1
669 %if ARCH_X86_32
670     push    r2
671     push    r1
672     push    r0
673 %else
674     sub     rsp, 8
675 %endif
676     call    r4
677 %if ARCH_X86_32
678     add     esp, 12
679 %else
680     add     rsp, 8
681 %endif
682     POP     r1
683     POP     r3
684     lea     r0, [r1 + 2*r3]
685     mov     r2, r3
686     sub     r3, mmsize
687     neg     r2
688     mova    m2, [ps_m1m1m1m1]
689 .loop:
690 %if mmsize == 8
691     PSWAPD  m0, [r1 + r3]
692     PSWAPD  m1, [r0 + r2]
693     pxor    m0, m2
694 %else
695     mova    m0, [r1 + r3]
696     mova    m1, [r0 + r2]
697     shufps  m0, m0, 0x1b
698     shufps  m1, m1, 0x1b
699     xorps   m0, m2
700 %endif
701     mova [r0 + r3], m1
702     mova [r1 + r2], m0
703     sub     r3, mmsize
704     add     r2, mmsize
705     jl      .loop
706 %if cpuflag(3dnow)
707     femms
708     RET
709 %else
710     REP_RET
711 %endif
712 %endmacro
713
714 %if ARCH_X86_32
715 INIT_MMX 3dnow
716 IMDCT_CALC_FUNC
717 INIT_MMX 3dnowext
718 IMDCT_CALC_FUNC
719 %endif
720
721 INIT_XMM sse
722 IMDCT_CALC_FUNC
723
724 %if ARCH_X86_32
725 INIT_MMX 3dnow
726 %define mulps pfmul
727 %define addps pfadd
728 %define subps pfsub
729 %define unpcklps punpckldq
730 %define unpckhps punpckhdq
731 DECL_PASS pass_3dnow, PASS_SMALL 1, [wq], [wq+o1q]
732 DECL_PASS pass_interleave_3dnow, PASS_BIG 0
733 %define pass_3dnowext pass_3dnow
734 %define pass_interleave_3dnowext pass_interleave_3dnow
735 %endif
736
737 %ifdef PIC
738 %define SECTION_REL - $$
739 %else
740 %define SECTION_REL
741 %endif
742
743 %macro DECL_FFT 1-2 ; nbits, suffix
744 %ifidn %0, 1
745 %xdefine fullsuffix SUFFIX
746 %else
747 %xdefine fullsuffix %2 %+ SUFFIX
748 %endif
749 %xdefine list_of_fft fft4 %+ SUFFIX SECTION_REL, fft8 %+ SUFFIX SECTION_REL
750 %if %1>=5
751 %xdefine list_of_fft list_of_fft, fft16 %+ SUFFIX SECTION_REL
752 %endif
753 %if %1>=6
754 %xdefine list_of_fft list_of_fft, fft32 %+ fullsuffix SECTION_REL
755 %endif
756
757 %assign n 1<<%1
758 %rep 17-%1
759 %assign n2 n/2
760 %assign n4 n/4
761 %xdefine list_of_fft list_of_fft, fft %+ n %+ fullsuffix SECTION_REL
762
763 align 16
764 fft %+ n %+ fullsuffix:
765     call fft %+ n2 %+ SUFFIX
766     add r0, n*4 - (n&(-2<<%1))
767     call fft %+ n4 %+ SUFFIX
768     add r0, n*2 - (n2&(-2<<%1))
769     call fft %+ n4 %+ SUFFIX
770     sub r0, n*6 + (n2&(-2<<%1))
771     lea r1, [cos_ %+ n]
772     mov r2d, n4/2
773     jmp pass %+ fullsuffix
774
775 %assign n n*2
776 %endrep
777 %undef n
778
779 align 8
780 dispatch_tab %+ fullsuffix: pointer list_of_fft
781 %endmacro ; DECL_FFT
782
783 %if HAVE_AVX_EXTERNAL
784 INIT_YMM avx
785 DECL_FFT 6
786 DECL_FFT 6, _interleave
787 %endif
788 INIT_XMM sse
789 DECL_FFT 5
790 DECL_FFT 5, _interleave
791 %if ARCH_X86_32
792 INIT_MMX 3dnow
793 DECL_FFT 4
794 DECL_FFT 4, _interleave
795 INIT_MMX 3dnowext
796 DECL_FFT 4
797 DECL_FFT 4, _interleave
798 %endif
799
800 INIT_XMM sse
801 %undef mulps
802 %undef addps
803 %undef subps
804 %undef unpcklps
805 %undef unpckhps
806
807 %macro PREROTATER 5 ;-2*k, 2*k, input+n4, tcos+n8, tsin+n8
808 %if mmsize == 8 ; j*2+2-n4, n4-2-j*2, input+n4, tcos+n8, tsin+n8
809     PSWAPD     m0, [%3+%2*4]
810     movq       m2, [%3+%1*4-8]
811     movq       m3, m0
812     punpckldq  m0, m2
813     punpckhdq  m2, m3
814     movd       m1, [%4+%1*2-4] ; tcos[j]
815     movd       m3, [%4+%2*2]   ; tcos[n4-j-1]
816     punpckldq  m1, [%5+%1*2-4] ; tsin[j]
817     punpckldq  m3, [%5+%2*2]   ; tsin[n4-j-1]
818
819     mova       m4, m0
820     PSWAPD     m5, m1
821     pfmul      m0, m1
822     pfmul      m4, m5
823     mova       m6, m2
824     PSWAPD     m5, m3
825     pfmul      m2, m3
826     pfmul      m6, m5
827 %if cpuflag(3dnowext)
828     pfpnacc    m0, m4
829     pfpnacc    m2, m6
830 %else
831     SBUTTERFLY dq, 0, 4, 1
832     SBUTTERFLY dq, 2, 6, 3
833     pxor       m4, m7
834     pxor       m6, m7
835     pfadd      m0, m4
836     pfadd      m2, m6
837 %endif
838 %else
839     movaps   xmm0, [%3+%2*4]
840     movaps   xmm1, [%3+%1*4-0x10]
841     movaps   xmm2, xmm0
842     shufps   xmm0, xmm1, 0x88
843     shufps   xmm1, xmm2, 0x77
844     movlps   xmm4, [%4+%2*2]
845     movlps   xmm5, [%5+%2*2+0x0]
846     movhps   xmm4, [%4+%1*2-0x8]
847     movhps   xmm5, [%5+%1*2-0x8]
848     movaps   xmm2, xmm0
849     movaps   xmm3, xmm1
850     mulps    xmm0, xmm5
851     mulps    xmm1, xmm4
852     mulps    xmm2, xmm4
853     mulps    xmm3, xmm5
854     subps    xmm1, xmm0
855     addps    xmm2, xmm3
856     movaps   xmm0, xmm1
857     unpcklps xmm1, xmm2
858     unpckhps xmm0, xmm2
859 %endif
860 %endmacro
861
862 %macro CMUL 6 ;j, xmm0, xmm1, 3, 4, 5
863     mulps      m6, %3, [%5+%1]
864     mulps      m7, %2, [%5+%1]
865     mulps      %2, %2, [%6+%1]
866     mulps      %3, %3, [%6+%1]
867     subps      %2, %2, m6
868     addps      %3, %3, m7
869 %endmacro
870
871 %macro POSROTATESHUF_AVX 5 ;j, k, z+n8, tcos+n8, tsin+n8
872 .post:
873     vmovaps      ymm1,   [%3+%1*2]
874     vmovaps      ymm0,   [%3+%1*2+0x20]
875     vmovaps      ymm3,   [%3+%2*2]
876     vmovaps      ymm2,   [%3+%2*2+0x20]
877
878     CMUL         %1, ymm0, ymm1, %3, %4, %5
879     CMUL         %2, ymm2, ymm3, %3, %4, %5
880     vshufps      ymm1, ymm1, ymm1, 0x1b
881     vshufps      ymm3, ymm3, ymm3, 0x1b
882     vperm2f128   ymm1, ymm1, ymm1, 0x01
883     vperm2f128   ymm3, ymm3, ymm3, 0x01
884     vunpcklps    ymm6, ymm2, ymm1
885     vunpckhps    ymm4, ymm2, ymm1
886     vunpcklps    ymm7, ymm0, ymm3
887     vunpckhps    ymm5, ymm0, ymm3
888
889     vextractf128 [%3+%1*2],      ymm7, 0
890     vextractf128 [%3+%1*2+0x10], ymm5, 0
891     vextractf128 [%3+%1*2+0x20], ymm7, 1
892     vextractf128 [%3+%1*2+0x30], ymm5, 1
893
894     vextractf128 [%3+%2*2],      ymm6, 0
895     vextractf128 [%3+%2*2+0x10], ymm4, 0
896     vextractf128 [%3+%2*2+0x20], ymm6, 1
897     vextractf128 [%3+%2*2+0x30], ymm4, 1
898     sub      %2,   0x20
899     add      %1,   0x20
900     jl       .post
901 %endmacro
902
903 %macro POSROTATESHUF 5 ;j, k, z+n8, tcos+n8, tsin+n8
904 .post:
905     movaps   xmm1, [%3+%1*2]
906     movaps   xmm0, [%3+%1*2+0x10]
907     CMUL     %1,   xmm0, xmm1, %3, %4, %5
908     movaps   xmm5, [%3+%2*2]
909     movaps   xmm4, [%3+%2*2+0x10]
910     CMUL     %2,   xmm4, xmm5, %3, %4, %5
911     shufps   xmm1, xmm1, 0x1b
912     shufps   xmm5, xmm5, 0x1b
913     movaps   xmm6, xmm4
914     unpckhps xmm4, xmm1
915     unpcklps xmm6, xmm1
916     movaps   xmm2, xmm0
917     unpcklps xmm0, xmm5
918     unpckhps xmm2, xmm5
919     movaps   [%3+%2*2],      xmm6
920     movaps   [%3+%2*2+0x10], xmm4
921     movaps   [%3+%1*2],      xmm0
922     movaps   [%3+%1*2+0x10], xmm2
923     sub      %2,   0x10
924     add      %1,   0x10
925     jl       .post
926 %endmacro
927
928 %macro CMUL_3DNOW 6
929     mova       m6, [%1+%2*2]
930     mova       %3, [%1+%2*2+8]
931     mova       %4, m6
932     mova       m7, %3
933     pfmul      m6, [%5+%2]
934     pfmul      %3, [%6+%2]
935     pfmul      %4, [%6+%2]
936     pfmul      m7, [%5+%2]
937     pfsub      %3, m6
938     pfadd      %4, m7
939 %endmacro
940
941 %macro POSROTATESHUF_3DNOW 5 ;j, k, z+n8, tcos+n8, tsin+n8
942 .post:
943     CMUL_3DNOW %3, %1, m0, m1, %4, %5
944     CMUL_3DNOW %3, %2, m2, m3, %4, %5
945     movd  [%3+%1*2+ 0], m0
946     movd  [%3+%2*2+12], m1
947     movd  [%3+%2*2+ 0], m2
948     movd  [%3+%1*2+12], m3
949     psrlq      m0, 32
950     psrlq      m1, 32
951     psrlq      m2, 32
952     psrlq      m3, 32
953     movd  [%3+%1*2+ 8], m0
954     movd  [%3+%2*2+ 4], m1
955     movd  [%3+%2*2+ 8], m2
956     movd  [%3+%1*2+ 4], m3
957     sub        %2, 8
958     add        %1, 8
959     jl         .post
960 %endmacro
961
962 %macro DECL_IMDCT 1
963 cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *input
964 %if ARCH_X86_64
965 %define rrevtab r7
966 %define rtcos   r8
967 %define rtsin   r9
968 %else
969 %define rrevtab r6
970 %define rtsin   r6
971 %define rtcos   r5
972 %endif
973     mov   r3d, [r0+FFTContext.mdctsize]
974     add   r2, r3
975     shr   r3, 1
976     mov   rtcos, [r0+FFTContext.tcos]
977     mov   rtsin, [r0+FFTContext.tsin]
978     add   rtcos, r3
979     add   rtsin, r3
980 %if ARCH_X86_64 == 0
981     push  rtcos
982     push  rtsin
983 %endif
984     shr   r3, 1
985     mov   rrevtab, [r0+FFTContext.revtab]
986     add   rrevtab, r3
987 %if ARCH_X86_64 == 0
988     push  rrevtab
989 %endif
990
991 %if mmsize == 8
992     sub   r3, 2
993 %else
994     sub   r3, 4
995 %endif
996 %if ARCH_X86_64 || mmsize == 8
997     xor   r4, r4
998     sub   r4, r3
999 %endif
1000 %if notcpuflag(3dnowext) && mmsize == 8
1001     movd  m7, [ps_m1m1m1m1]
1002 %endif
1003 .pre:
1004 %if ARCH_X86_64 == 0
1005 ;unspill
1006 %if mmsize != 8
1007     xor   r4, r4
1008     sub   r4, r3
1009 %endif
1010     mov   rtcos, [esp+8]
1011     mov   rtsin, [esp+4]
1012 %endif
1013
1014     PREROTATER r4, r3, r2, rtcos, rtsin
1015 %if mmsize == 8
1016     mov    r6, [esp]                ; rrevtab = ptr+n8
1017     movzx  r5,  word [rrevtab+r4-2] ; rrevtab[j]
1018     movzx  r6,  word [rrevtab+r3]   ; rrevtab[n4-j-1]
1019     mova [r1+r5*8], m0
1020     mova [r1+r6*8], m2
1021     add    r4, 2
1022     sub    r3, 2
1023 %else
1024 %if ARCH_X86_64
1025     movzx  r5,  word [rrevtab+r4-4]
1026     movzx  r6,  word [rrevtab+r4-2]
1027     movzx  r10, word [rrevtab+r3]
1028     movzx  r11, word [rrevtab+r3+2]
1029     movlps [r1+r5 *8], xmm0
1030     movhps [r1+r6 *8], xmm0
1031     movlps [r1+r10*8], xmm1
1032     movhps [r1+r11*8], xmm1
1033     add    r4, 4
1034 %else
1035     mov    r6, [esp]
1036     movzx  r5, word [r6+r4-4]
1037     movzx  r4, word [r6+r4-2]
1038     movlps [r1+r5*8], xmm0
1039     movhps [r1+r4*8], xmm0
1040     movzx  r5, word [r6+r3]
1041     movzx  r4, word [r6+r3+2]
1042     movlps [r1+r5*8], xmm1
1043     movhps [r1+r4*8], xmm1
1044 %endif
1045     sub    r3, 4
1046 %endif
1047     jns    .pre
1048
1049     mov  r5, r0
1050     mov  r6, r1
1051     mov  r0, r1
1052     mov  r1d, [r5+FFTContext.nbits]
1053
1054     FFT_DISPATCH SUFFIX, r1
1055
1056     mov  r0d, [r5+FFTContext.mdctsize]
1057     add  r6, r0
1058     shr  r0, 1
1059 %if ARCH_X86_64 == 0
1060 %define rtcos r2
1061 %define rtsin r3
1062     mov  rtcos, [esp+8]
1063     mov  rtsin, [esp+4]
1064 %endif
1065     neg  r0
1066     mov  r1, -mmsize
1067     sub  r1, r0
1068     %1 r0, r1, r6, rtcos, rtsin
1069 %if ARCH_X86_64 == 0
1070     add esp, 12
1071 %endif
1072 %if mmsize == 8
1073     femms
1074 %endif
1075     RET
1076 %endmacro
1077
1078 DECL_IMDCT POSROTATESHUF
1079
1080 %if ARCH_X86_32
1081 INIT_MMX 3dnow
1082 DECL_IMDCT POSROTATESHUF_3DNOW
1083
1084 INIT_MMX 3dnowext
1085 DECL_IMDCT POSROTATESHUF_3DNOW
1086 %endif
1087
1088 INIT_YMM avx
1089
1090 %if HAVE_AVX_EXTERNAL
1091 DECL_IMDCT POSROTATESHUF_AVX
1092 %endif