Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libavresample / x86 / audio_mix.asm
1 ;******************************************************************************
2 ;* x86 optimized channel mixing
3 ;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
4 ;*
5 ;* This file is part of Libav.
6 ;*
7 ;* Libav 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 ;* Libav 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 Libav; if not, write to the Free Software
19 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 ;******************************************************************************
21
22 %include "libavutil/x86/x86util.asm"
23 %include "util.asm"
24
25 SECTION_TEXT
26
27 ;-----------------------------------------------------------------------------
28 ; void ff_mix_2_to_1_fltp_flt(float **src, float **matrix, int len,
29 ;                             int out_ch, int in_ch);
30 ;-----------------------------------------------------------------------------
31
32 %macro MIX_2_TO_1_FLTP_FLT 0
33 cglobal mix_2_to_1_fltp_flt, 3,4,6, src, matrix, len, src1
34     mov       src1q, [srcq+gprsize]
35     mov        srcq, [srcq        ]
36     sub       src1q, srcq
37     mov     matrixq, [matrixq  ]
38     VBROADCASTSS m4, [matrixq  ]
39     VBROADCASTSS m5, [matrixq+4]
40     ALIGN 16
41 .loop:
42     mulps        m0, m4, [srcq             ]
43     mulps        m1, m5, [srcq+src1q       ]
44     mulps        m2, m4, [srcq+      mmsize]
45     mulps        m3, m5, [srcq+src1q+mmsize]
46     addps        m0, m0, m1
47     addps        m2, m2, m3
48     mova  [srcq       ], m0
49     mova  [srcq+mmsize], m2
50     add        srcq, mmsize*2
51     sub        lend, mmsize*2/4
52     jg .loop
53     REP_RET
54 %endmacro
55
56 INIT_XMM sse
57 MIX_2_TO_1_FLTP_FLT
58 %if HAVE_AVX_EXTERNAL
59 INIT_YMM avx
60 MIX_2_TO_1_FLTP_FLT
61 %endif
62
63 ;-----------------------------------------------------------------------------
64 ; void ff_mix_2_to_1_s16p_flt(int16_t **src, float **matrix, int len,
65 ;                             int out_ch, int in_ch);
66 ;-----------------------------------------------------------------------------
67
68 %macro MIX_2_TO_1_S16P_FLT 0
69 cglobal mix_2_to_1_s16p_flt, 3,4,6, src, matrix, len, src1
70     mov       src1q, [srcq+gprsize]
71     mov        srcq, [srcq]
72     sub       src1q, srcq
73     mov     matrixq, [matrixq  ]
74     VBROADCASTSS m4, [matrixq  ]
75     VBROADCASTSS m5, [matrixq+4]
76     ALIGN 16
77 .loop:
78     mova         m0, [srcq      ]
79     mova         m2, [srcq+src1q]
80     S16_TO_S32_SX 0, 1
81     S16_TO_S32_SX 2, 3
82     cvtdq2ps     m0, m0
83     cvtdq2ps     m1, m1
84     cvtdq2ps     m2, m2
85     cvtdq2ps     m3, m3
86     mulps        m0, m4
87     mulps        m1, m4
88     mulps        m2, m5
89     mulps        m3, m5
90     addps        m0, m2
91     addps        m1, m3
92     cvtps2dq     m0, m0
93     cvtps2dq     m1, m1
94     packssdw     m0, m1
95     mova     [srcq], m0
96     add        srcq, mmsize
97     sub        lend, mmsize/2
98     jg .loop
99     REP_RET
100 %endmacro
101
102 INIT_XMM sse2
103 MIX_2_TO_1_S16P_FLT
104 INIT_XMM sse4
105 MIX_2_TO_1_S16P_FLT
106
107 ;-----------------------------------------------------------------------------
108 ; void ff_mix_2_to_1_s16p_q8(int16_t **src, int16_t **matrix, int len,
109 ;                            int out_ch, int in_ch);
110 ;-----------------------------------------------------------------------------
111
112 INIT_XMM sse2
113 cglobal mix_2_to_1_s16p_q8, 3,4,6, src, matrix, len, src1
114     mov       src1q, [srcq+gprsize]
115     mov        srcq, [srcq]
116     sub       src1q, srcq
117     mov     matrixq, [matrixq]
118     movd         m4, [matrixq]
119     movd         m5, [matrixq]
120     SPLATW       m4, m4, 0
121     SPLATW       m5, m5, 1
122     pxor         m0, m0
123     punpcklwd    m4, m0
124     punpcklwd    m5, m0
125     ALIGN 16
126 .loop:
127     mova         m0, [srcq      ]
128     mova         m2, [srcq+src1q]
129     punpckhwd    m1, m0, m0
130     punpcklwd    m0, m0
131     punpckhwd    m3, m2, m2
132     punpcklwd    m2, m2
133     pmaddwd      m0, m4
134     pmaddwd      m1, m4
135     pmaddwd      m2, m5
136     pmaddwd      m3, m5
137     paddd        m0, m2
138     paddd        m1, m3
139     psrad        m0, 8
140     psrad        m1, 8
141     packssdw     m0, m1
142     mova     [srcq], m0
143     add        srcq, mmsize
144     sub        lend, mmsize/2
145     jg .loop
146     REP_RET
147
148 ;-----------------------------------------------------------------------------
149 ; void ff_mix_1_to_2_fltp_flt(float **src, float **matrix, int len,
150 ;                             int out_ch, int in_ch);
151 ;-----------------------------------------------------------------------------
152
153 %macro MIX_1_TO_2_FLTP_FLT 0
154 cglobal mix_1_to_2_fltp_flt, 3,5,4, src0, matrix0, len, src1, matrix1
155     mov       src1q, [src0q+gprsize]
156     mov       src0q, [src0q]
157     sub       src1q, src0q
158     mov    matrix1q, [matrix0q+gprsize]
159     mov    matrix0q, [matrix0q]
160     VBROADCASTSS m2, [matrix0q]
161     VBROADCASTSS m3, [matrix1q]
162     ALIGN 16
163 .loop:
164     mova         m0, [src0q]
165     mulps        m1, m0, m3
166     mulps        m0, m0, m2
167     mova  [src0q      ], m0
168     mova  [src0q+src1q], m1
169     add       src0q, mmsize
170     sub        lend, mmsize/4
171     jg .loop
172     REP_RET
173 %endmacro
174
175 INIT_XMM sse
176 MIX_1_TO_2_FLTP_FLT
177 %if HAVE_AVX_EXTERNAL
178 INIT_YMM avx
179 MIX_1_TO_2_FLTP_FLT
180 %endif
181
182 ;-----------------------------------------------------------------------------
183 ; void ff_mix_1_to_2_s16p_flt(int16_t **src, float **matrix, int len,
184 ;                             int out_ch, int in_ch);
185 ;-----------------------------------------------------------------------------
186
187 %macro MIX_1_TO_2_S16P_FLT 0
188 cglobal mix_1_to_2_s16p_flt, 3,5,6, src0, matrix0, len, src1, matrix1
189     mov       src1q, [src0q+gprsize]
190     mov       src0q, [src0q]
191     sub       src1q, src0q
192     mov    matrix1q, [matrix0q+gprsize]
193     mov    matrix0q, [matrix0q]
194     VBROADCASTSS m4, [matrix0q]
195     VBROADCASTSS m5, [matrix1q]
196     ALIGN 16
197 .loop:
198     mova         m0, [src0q]
199     S16_TO_S32_SX 0, 2
200     cvtdq2ps     m0, m0
201     cvtdq2ps     m2, m2
202     mulps        m1, m0, m5
203     mulps        m0, m0, m4
204     mulps        m3, m2, m5
205     mulps        m2, m2, m4
206     cvtps2dq     m0, m0
207     cvtps2dq     m1, m1
208     cvtps2dq     m2, m2
209     cvtps2dq     m3, m3
210     packssdw     m0, m2
211     packssdw     m1, m3
212     mova  [src0q      ], m0
213     mova  [src0q+src1q], m1
214     add       src0q, mmsize
215     sub        lend, mmsize/2
216     jg .loop
217     REP_RET
218 %endmacro
219
220 INIT_XMM sse2
221 MIX_1_TO_2_S16P_FLT
222 INIT_XMM sse4
223 MIX_1_TO_2_S16P_FLT
224 %if HAVE_AVX_EXTERNAL
225 INIT_XMM avx
226 MIX_1_TO_2_S16P_FLT
227 %endif
228
229 ;-----------------------------------------------------------------------------
230 ; void ff_mix_3_8_to_1_2_fltp/s16p_flt(float/int16_t **src, float **matrix,
231 ;                                      int len, int out_ch, int in_ch);
232 ;-----------------------------------------------------------------------------
233
234 %macro MIX_3_8_TO_1_2_FLT 3 ; %1 = in channels, %2 = out channels, %3 = s16p or fltp
235 ; define some names to make the code clearer
236 %assign  in_channels %1
237 %assign out_channels %2
238 %assign stereo out_channels - 1
239 %ifidn %3, s16p
240     %assign is_s16 1
241 %else
242     %assign is_s16 0
243 %endif
244
245 ; determine how many matrix elements must go on the stack vs. mmregs
246 %assign matrix_elements in_channels * out_channels
247 %if is_s16
248     %if stereo
249         %assign needed_mmregs 7
250     %else
251         %assign needed_mmregs 5
252     %endif
253 %else
254     %if stereo
255         %assign needed_mmregs 4
256     %else
257         %assign needed_mmregs 3
258     %endif
259 %endif
260 %assign matrix_elements_mm num_mmregs - needed_mmregs
261 %if matrix_elements < matrix_elements_mm
262     %assign matrix_elements_mm matrix_elements
263 %endif
264 %if matrix_elements_mm < matrix_elements
265     %assign matrix_elements_stack matrix_elements - matrix_elements_mm
266 %else
267     %assign matrix_elements_stack 0
268 %endif
269
270 cglobal mix_%1_to_%2_%3_flt, 3,in_channels+2,needed_mmregs+matrix_elements_mm, src0, src1, len, src2, src3, src4, src5, src6, src7
271
272 ; get aligned stack space if needed
273 %if matrix_elements_stack > 0
274     %if mmsize == 32
275     %assign bkpreg %1 + 1
276     %define bkpq r %+ bkpreg %+ q
277     mov           bkpq, rsp
278     and           rsp, ~(mmsize-1)
279     sub           rsp, matrix_elements_stack * mmsize
280     %else
281     %assign matrix_stack_size matrix_elements_stack * mmsize
282     %assign pad matrix_stack_size + (mmsize - gprsize) - (stack_offset & (mmsize - gprsize))
283     ; on x86-32 for 7 and 8 channels we need more stack space for src pointers
284     %if ARCH_X86_32 && in_channels >= 7
285     %assign pad pad + 0x10
286     %define src5m [rsp+matrix_stack_size+0]
287     %define src6m [rsp+matrix_stack_size+4]
288     %define src7m [rsp+matrix_stack_size+8]
289     %endif
290     SUB           rsp, pad
291     %endif
292 %endif
293
294 ; load matrix pointers
295 %define matrix0q r1q
296 %define matrix1q r3q
297 %if stereo
298     mov      matrix1q, [matrix0q+gprsize]
299 %endif
300     mov      matrix0q, [matrix0q]
301
302 ; define matrix coeff names
303 %assign %%i 0
304 %assign %%j needed_mmregs
305 %rep in_channels
306     %if %%i >= matrix_elements_mm
307         CAT_XDEFINE mx_stack_0_, %%i, 1
308         CAT_XDEFINE mx_0_, %%i, [rsp+(%%i-matrix_elements_mm)*mmsize]
309     %else
310         CAT_XDEFINE mx_stack_0_, %%i, 0
311         CAT_XDEFINE mx_0_, %%i, m %+ %%j
312         %assign %%j %%j+1
313     %endif
314     %assign %%i %%i+1
315 %endrep
316 %if stereo
317 %assign %%i 0
318 %rep in_channels
319     %if in_channels + %%i >= matrix_elements_mm
320         CAT_XDEFINE mx_stack_1_, %%i, 1
321         CAT_XDEFINE mx_1_, %%i, [rsp+(in_channels+%%i-matrix_elements_mm)*mmsize]
322     %else
323         CAT_XDEFINE mx_stack_1_, %%i, 0
324         CAT_XDEFINE mx_1_, %%i, m %+ %%j
325         %assign %%j %%j+1
326     %endif
327     %assign %%i %%i+1
328 %endrep
329 %endif
330
331 ; load/splat matrix coeffs
332 %assign %%i 0
333 %rep in_channels
334     %if mx_stack_0_ %+ %%i
335         VBROADCASTSS m0, [matrix0q+4*%%i]
336         mova  mx_0_ %+ %%i, m0
337     %else
338         VBROADCASTSS mx_0_ %+ %%i, [matrix0q+4*%%i]
339     %endif
340     %if stereo
341     %if mx_stack_1_ %+ %%i
342         VBROADCASTSS m0, [matrix1q+4*%%i]
343         mova  mx_1_ %+ %%i, m0
344     %else
345         VBROADCASTSS mx_1_ %+ %%i, [matrix1q+4*%%i]
346     %endif
347     %endif
348     %assign %%i %%i+1
349 %endrep
350
351 ; load channel pointers to registers as offsets from the first channel pointer
352 %if ARCH_X86_64
353     movsxd       lenq, r2d
354 %endif
355     shl          lenq, 2-is_s16
356 %assign %%i 1
357 %rep (in_channels - 1)
358     %if ARCH_X86_32 && in_channels >= 7 && %%i >= 5
359     mov         src5q, [src0q+%%i*gprsize]
360     add         src5q, lenq
361     mov         src %+ %%i %+ m, src5q
362     %else
363     mov         src %+ %%i %+ q, [src0q+%%i*gprsize]
364     add         src %+ %%i %+ q, lenq
365     %endif
366     %assign %%i %%i+1
367 %endrep
368     mov         src0q, [src0q]
369     add         src0q, lenq
370     neg          lenq
371 .loop:
372 ; for x86-32 with 7-8 channels we do not have enough gp registers for all src
373 ; pointers, so we have to load some of them from the stack each time
374 %define copy_src_from_stack ARCH_X86_32 && in_channels >= 7 && %%i >= 5
375 %if is_s16
376     ; mix with s16p input
377     mova           m0, [src0q+lenq]
378     S16_TO_S32_SX   0, 1
379     cvtdq2ps       m0, m0
380     cvtdq2ps       m1, m1
381     %if stereo
382     mulps          m2, m0, mx_1_0
383     mulps          m3, m1, mx_1_0
384     %endif
385     mulps          m0, m0, mx_0_0
386     mulps          m1, m1, mx_0_0
387 %assign %%i 1
388 %rep (in_channels - 1)
389     %if copy_src_from_stack
390         %define src_ptr src5q
391     %else
392         %define src_ptr src %+ %%i %+ q
393     %endif
394     %if stereo
395     %if copy_src_from_stack
396     mov       src_ptr, src %+ %%i %+ m
397     %endif
398     mova           m4, [src_ptr+lenq]
399     S16_TO_S32_SX   4, 5
400     cvtdq2ps       m4, m4
401     cvtdq2ps       m5, m5
402     fmaddps        m2, m4, mx_1_ %+ %%i, m2, m6
403     fmaddps        m3, m5, mx_1_ %+ %%i, m3, m6
404     fmaddps        m0, m4, mx_0_ %+ %%i, m0, m4
405     fmaddps        m1, m5, mx_0_ %+ %%i, m1, m5
406     %else
407     %if copy_src_from_stack
408     mov       src_ptr, src %+ %%i %+ m
409     %endif
410     mova           m2, [src_ptr+lenq]
411     S16_TO_S32_SX   2, 3
412     cvtdq2ps       m2, m2
413     cvtdq2ps       m3, m3
414     fmaddps        m0, m2, mx_0_ %+ %%i, m0, m4
415     fmaddps        m1, m3, mx_0_ %+ %%i, m1, m4
416     %endif
417     %assign %%i %%i+1
418 %endrep
419     %if stereo
420     cvtps2dq       m2, m2
421     cvtps2dq       m3, m3
422     packssdw       m2, m3
423     mova [src1q+lenq], m2
424     %endif
425     cvtps2dq       m0, m0
426     cvtps2dq       m1, m1
427     packssdw       m0, m1
428     mova [src0q+lenq], m0
429 %else
430     ; mix with fltp input
431     %if stereo || mx_stack_0_0
432     mova           m0, [src0q+lenq]
433     %endif
434     %if stereo
435     mulps          m1, m0, mx_1_0
436     %endif
437     %if stereo || mx_stack_0_0
438     mulps          m0, m0, mx_0_0
439     %else
440     mulps          m0, [src0q+lenq], mx_0_0
441     %endif
442 %assign %%i 1
443 %rep (in_channels - 1)
444     %if copy_src_from_stack
445         %define src_ptr src5q
446         mov   src_ptr, src %+ %%i %+ m
447     %else
448         %define src_ptr src %+ %%i %+ q
449     %endif
450     ; avoid extra load for mono if matrix is in a mm register
451     %if stereo || mx_stack_0_ %+ %%i
452     mova           m2, [src_ptr+lenq]
453     %endif
454     %if stereo
455     fmaddps        m1, m2, mx_1_ %+ %%i, m1, m3
456     %endif
457     %if stereo || mx_stack_0_ %+ %%i
458     fmaddps        m0, m2, mx_0_ %+ %%i, m0, m2
459     %else
460     fmaddps        m0, mx_0_ %+ %%i, [src_ptr+lenq], m0, m1
461     %endif
462     %assign %%i %%i+1
463 %endrep
464     mova [src0q+lenq], m0
465     %if stereo
466     mova [src1q+lenq], m1
467     %endif
468 %endif
469
470     add          lenq, mmsize
471     jl .loop
472 ; restore stack pointer
473 %if matrix_elements_stack > 0
474     %if mmsize == 32
475     mov           rsp, bkpq
476     %else
477     ADD           rsp, pad
478     %endif
479 %endif
480 ; zero ymm high halves
481 %if mmsize == 32
482     vzeroupper
483 %endif
484     RET
485 %endmacro
486
487 %macro MIX_3_8_TO_1_2_FLT_FUNCS 0
488 %assign %%i 3
489 %rep 6
490     INIT_XMM sse
491     MIX_3_8_TO_1_2_FLT %%i, 1, fltp
492     MIX_3_8_TO_1_2_FLT %%i, 2, fltp
493     INIT_XMM sse2
494     MIX_3_8_TO_1_2_FLT %%i, 1, s16p
495     MIX_3_8_TO_1_2_FLT %%i, 2, s16p
496     INIT_XMM sse4
497     MIX_3_8_TO_1_2_FLT %%i, 1, s16p
498     MIX_3_8_TO_1_2_FLT %%i, 2, s16p
499     ; do not use ymm AVX or FMA4 in x86-32 for 6 or more channels due to stack alignment issues
500     %if HAVE_AVX_EXTERNAL
501     %if ARCH_X86_64 || %%i < 6
502     INIT_YMM avx
503     %else
504     INIT_XMM avx
505     %endif
506     MIX_3_8_TO_1_2_FLT %%i, 1, fltp
507     MIX_3_8_TO_1_2_FLT %%i, 2, fltp
508     INIT_XMM avx
509     MIX_3_8_TO_1_2_FLT %%i, 1, s16p
510     MIX_3_8_TO_1_2_FLT %%i, 2, s16p
511     %endif
512     %if HAVE_FMA4_EXTERNAL
513     %if ARCH_X86_64 || %%i < 6
514     INIT_YMM fma4
515     %else
516     INIT_XMM fma4
517     %endif
518     MIX_3_8_TO_1_2_FLT %%i, 1, fltp
519     MIX_3_8_TO_1_2_FLT %%i, 2, fltp
520     INIT_XMM fma4
521     MIX_3_8_TO_1_2_FLT %%i, 1, s16p
522     MIX_3_8_TO_1_2_FLT %%i, 2, s16p
523     %endif
524     %assign %%i %%i+1
525 %endrep
526 %endmacro
527
528 MIX_3_8_TO_1_2_FLT_FUNCS