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