On 10/28/2015 11:38 AM, Diego Biurrun wrote:
> diff --git a/libavcodec/x86/ac3dsp_downmix.asm 
> b/libavcodec/x86/ac3dsp_downmix.asm
> new file mode 100644
> index 0000000..d7fd8ac
> --- /dev/null
> +++ b/libavcodec/x86/ac3dsp_downmix.asm
> @@ -0,0 +1,199 @@
> +;*****************************************************************************
> +;* x86-optimized AC-3 downmixing
> +;* Copyright (c) 2012 Justin Ruggles
> +;*
> +;* This file is part of Libav.
> +;*
> +;* Libav is free software; you can redistribute it and/or
> +;* modify it under the terms of the GNU Lesser General Public
> +;* License as published by the Free Software Foundation; either
> +;* version 2.1 of the License, or (at your option) any later version.
> +;*
> +;* Libav is distributed in the hope that it will be useful,
> +;* but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +;* Lesser General Public License for more details.
> +;*
> +;* You should have received a copy of the GNU Lesser General Public
> +;* License along with Libav; if not, write to the Free Software
> +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
> +;******************************************************************************
> +
> +;******************************************************************************
> +;* This is based on the channel mixing asm in libavresample, but it is
> +;* simplified for only float coefficients and only 3 to 6 channels.
> +;******************************************************************************
> +
> +%include "libavutil/x86/x86util.asm"
> +
> +SECTION .text
> +
> +;-----------------------------------------------------------------------------
> +; functions to downmix from 3 to 6 channels to mono or stereo
> +; void ff_ac3_downmix_*(float **samples, float **matrix, int len);
> +;-----------------------------------------------------------------------------
> +
> +%macro AC3_DOWNMIX 2 ; %1 = in channels, %2 = out channels
> +; define some names to make the code clearer
> +%assign  in_channels %1
> +%assign out_channels %2
> +%assign stereo out_channels - 1
> +
> +; determine how many matrix elements must go on the stack vs. mmregs
> +%assign matrix_elements in_channels * out_channels
> +%if stereo
> +    %assign needed_mmregs 4
> +%else
> +    %assign needed_mmregs 3
> +%endif
> +%assign matrix_elements_mm num_mmregs - needed_mmregs
> +%if matrix_elements < matrix_elements_mm
> +    %assign matrix_elements_mm matrix_elements
> +%endif
> +%assign total_mmregs needed_mmregs+matrix_elements_mm
> +%if matrix_elements_mm < matrix_elements
> +    %assign matrix_elements_stack matrix_elements - matrix_elements_mm
> +%else
> +    %assign matrix_elements_stack 0
> +%endif
> +
> +cglobal ac3_downmix_%1_to_%2, 
> 3,in_channels+1,total_mmregs,0-matrix_elements_stack*mmsize, src0, src1, len, 
> src2, src3, src4, src5
> +
> +; load matrix pointers
> +%define matrix0q r1q
> +%define matrix1q r3q
> +%if stereo
> +    mov      matrix1q, [matrix0q+gprsize]
> +%endif
> +    mov      matrix0q, [matrix0q]
> +
> +; define matrix coeff names
> +%assign %%i 0
> +%assign %%j needed_mmregs
> +%rep in_channels
> +    %if %%i >= matrix_elements_mm
> +        CAT_XDEFINE mx_stack_0_, %%i, 1
> +        CAT_XDEFINE mx_0_, %%i, [rsp+(%%i-matrix_elements_mm)*mmsize]
> +    %else
> +        CAT_XDEFINE mx_stack_0_, %%i, 0
> +        CAT_XDEFINE mx_0_, %%i, m %+ %%j
> +        %assign %%j %%j+1
> +    %endif
> +    %assign %%i %%i+1
> +%endrep
> +%if stereo
> +%assign %%i 0
> +%rep in_channels
> +    %if in_channels + %%i >= matrix_elements_mm
> +        CAT_XDEFINE mx_stack_1_, %%i, 1
> +        CAT_XDEFINE mx_1_, %%i, 
> [rsp+(in_channels+%%i-matrix_elements_mm)*mmsize]
> +    %else
> +        CAT_XDEFINE mx_stack_1_, %%i, 0
> +        CAT_XDEFINE mx_1_, %%i, m %+ %%j
> +        %assign %%j %%j+1
> +    %endif
> +    %assign %%i %%i+1
> +%endrep
> +%endif
> +
> +; load/splat matrix coeffs
> +%assign %%i 0
> +%rep in_channels
> +    %if mx_stack_0_ %+ %%i
> +        VBROADCASTSS m0, [matrix0q+4*%%i]
> +        mova  mx_0_ %+ %%i, m0
> +    %else
> +        VBROADCASTSS mx_0_ %+ %%i, [matrix0q+4*%%i]
> +    %endif
> +    %if stereo
> +    %if mx_stack_1_ %+ %%i
> +        VBROADCASTSS m0, [matrix1q+4*%%i]
> +        mova  mx_1_ %+ %%i, m0
> +    %else
> +        VBROADCASTSS mx_1_ %+ %%i, [matrix1q+4*%%i]
> +    %endif
> +    %endif
> +    %assign %%i %%i+1
> +%endrep
> +
> +    lea          lenq, [4*r2d]
> +    ; load channel pointers to registers
> +%assign %%i 1
> +%rep (in_channels - 1)
> +    mov         src %+ %%i %+ q, [src0q+%%i*gprsize]
> +    add         src %+ %%i %+ q, lenq
> +    %assign %%i %%i+1
> +%endrep
> +    mov         src0q, [src0q]
> +    add         src0q, lenq
> +    neg          lenq
> +.loop:
> +    %if stereo || mx_stack_0_0
> +    mova           m0, [src0q+lenq]
> +    %endif
> +    %if stereo
> +    mulps          m1, m0, mx_1_0
> +    %endif
> +    %if stereo || mx_stack_0_0
> +    mulps          m0, m0, mx_0_0
> +    %else
> +    mulps          m0, mx_0_0, [src0q+lenq]
> +    %endif
> +%assign %%i 1
> +%rep (in_channels - 1)
> +    %define src_ptr src %+ %%i %+ q
> +    ; avoid extra load for mono if matrix is in a mm register
> +    %if stereo || mx_stack_0_ %+ %%i
> +    mova           m2, [src_ptr+lenq]
> +    %endif
> +    %if stereo
> +    FMULADD_PS     m1, m2, mx_1_ %+ %%i, m1, m3
> +    %endif
> +    %if stereo || mx_stack_0_ %+ %%i
> +    FMULADD_PS     m0, m2, mx_0_ %+ %%i, m0, m2
> +    %else
> +    FMULADD_PS     m0, mx_0_ %+ %%i, [src_ptr+lenq], m0, m1
> +    %endif
> +    %assign %%i %%i+1
> +%endrep
> +    mova [src0q+lenq], m0
> +    %if stereo
> +    mova [src1q+lenq], m1
> +    %endif
> +
> +    add          lenq, mmsize
> +    jl .loop
> +    RET
> +%endmacro
> +
> +%macro AC3_DOWNMIX_FUNCS 0
> +%assign %%i 3
> +%rep 4
> +    INIT_XMM sse
> +    AC3_DOWNMIX %%i, 1
> +    AC3_DOWNMIX %%i, 2
> +    ; Do not use ymm AVX or FMA4 on x86-32 for 6 channels due to stack 
> alignment
> +    ; issues. We are not guaranteed a 32-byte aligned stack, so we have to 
> use
> +    ; an extra register to save/restore the stack pointer. For 6 channels on
> +    ; x86-32 we do not have an extra register available.
> +    %if ARCH_X86_64 || %%i < 6
> +    INIT_YMM avx
> +    %else
> +    INIT_XMM avx
> +    %endif
> +    AC3_DOWNMIX %%i, 1
> +    AC3_DOWNMIX %%i, 2
> +    %if HAVE_FMA4_EXTERNAL
> +    %if ARCH_X86_64 || %%i < 6
> +    INIT_YMM fma4

FMA4 is AMD exclusive, deprecated, and will not be featured on their upcoming 
architecture.
Also, the only CPUs that support it don't benefit from asm using 32byte wide 
regs (ymm).

You have two options. One is to change this into FMA3 and call it a day. FMA3 
works on both
Intel and AMD CPUs (Except for first gen Bulldozer, which is fma4 only). The 
other is making
two versions, one FMA3 and one FMA4, the latter using exclusively xmm regs, and 
the former
both xmm or ymm as needed (What you already wrote).
The first option is the simplest, so I'd say go with that. You'll however have 
to check for
the avxslow flag for any function using ymm regs (avx or fma) so they are not 
used on
Bulldozer based CPU. On those, an xmm variant should be used instead.

This code looks a lot like what's already in avresample, so the same should be 
done there if
possible.
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to