1cabdff1aSopenharmony_ci;******************************************************************************
2cabdff1aSopenharmony_ci;* linear least squares model
3cabdff1aSopenharmony_ci;*
4cabdff1aSopenharmony_ci;* Copyright (c) 2013 Loren Merritt
5cabdff1aSopenharmony_ci;*
6cabdff1aSopenharmony_ci;* This file is part of FFmpeg.
7cabdff1aSopenharmony_ci;*
8cabdff1aSopenharmony_ci;* FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci;* modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci;* License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci;* version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci;*
13cabdff1aSopenharmony_ci;* FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci;* but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci;* Lesser General Public License for more details.
17cabdff1aSopenharmony_ci;*
18cabdff1aSopenharmony_ci;* You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci;* License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci;******************************************************************************
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci%include "libavutil/x86/x86util.asm"
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ciSECTION .text
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci%define MAX_VARS 32
28cabdff1aSopenharmony_ci%define MAX_VARS_ALIGN (MAX_VARS+4)
29cabdff1aSopenharmony_ci%define COVAR_STRIDE MAX_VARS_ALIGN*8
30cabdff1aSopenharmony_ci%define COVAR(x,y) [covarq + (x)*8 + (y)*COVAR_STRIDE]
31cabdff1aSopenharmony_ci
32cabdff1aSopenharmony_cistruc LLSModel
33cabdff1aSopenharmony_ci    .covariance:  resq MAX_VARS_ALIGN*MAX_VARS_ALIGN
34cabdff1aSopenharmony_ci    .coeff:       resq MAX_VARS*MAX_VARS
35cabdff1aSopenharmony_ci    .variance:    resq MAX_VARS
36cabdff1aSopenharmony_ci    .indep_count: resd 1
37cabdff1aSopenharmony_ciendstruc
38cabdff1aSopenharmony_ci
39cabdff1aSopenharmony_ci%macro ADDPD_MEM 2
40cabdff1aSopenharmony_ci%if cpuflag(avx)
41cabdff1aSopenharmony_ci    vaddpd %2, %2, %1
42cabdff1aSopenharmony_ci%else
43cabdff1aSopenharmony_ci    addpd  %2, %1
44cabdff1aSopenharmony_ci%endif
45cabdff1aSopenharmony_ci    mova   %1, %2
46cabdff1aSopenharmony_ci%endmacro
47cabdff1aSopenharmony_ci
48cabdff1aSopenharmony_ciINIT_XMM sse2
49cabdff1aSopenharmony_ci%define movdqa movaps
50cabdff1aSopenharmony_cicglobal update_lls, 2,5,8, ctx, var, i, j, covar2
51cabdff1aSopenharmony_ci    %define covarq ctxq
52cabdff1aSopenharmony_ci    mov     id, [ctxq + LLSModel.indep_count]
53cabdff1aSopenharmony_ci    lea   varq, [varq + iq*8]
54cabdff1aSopenharmony_ci    neg     iq
55cabdff1aSopenharmony_ci    mov covar2q, covarq
56cabdff1aSopenharmony_ci.loopi:
57cabdff1aSopenharmony_ci    ; Compute all 3 pairwise products of a 2x2 block that lies on the diagonal
58cabdff1aSopenharmony_ci    mova    m1, [varq + iq*8]
59cabdff1aSopenharmony_ci    mova    m3, [varq + iq*8 + 16]
60cabdff1aSopenharmony_ci    pshufd  m4, m1, q1010
61cabdff1aSopenharmony_ci    pshufd  m5, m1, q3232
62cabdff1aSopenharmony_ci    pshufd  m6, m3, q1010
63cabdff1aSopenharmony_ci    pshufd  m7, m3, q3232
64cabdff1aSopenharmony_ci    mulpd   m0, m1, m4
65cabdff1aSopenharmony_ci    mulpd   m1, m1, m5
66cabdff1aSopenharmony_ci    lea covarq, [covar2q + 16]
67cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(-2,0), m0
68cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(-2,1), m1
69cabdff1aSopenharmony_ci    lea     jq, [iq + 2]
70cabdff1aSopenharmony_ci    cmp     jd, -2
71cabdff1aSopenharmony_ci    jg .skip4x4
72cabdff1aSopenharmony_ci.loop4x4:
73cabdff1aSopenharmony_ci    ; Compute all 16 pairwise products of a 4x4 block
74cabdff1aSopenharmony_ci    mulpd   m0, m4, m3
75cabdff1aSopenharmony_ci    mulpd   m1, m5, m3
76cabdff1aSopenharmony_ci    mulpd   m2, m6, m3
77cabdff1aSopenharmony_ci    mulpd   m3, m3, m7
78cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,0), m0
79cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,1), m1
80cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,2), m2
81cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,3), m3
82cabdff1aSopenharmony_ci    mova    m3, [varq + jq*8 + 16]
83cabdff1aSopenharmony_ci    mulpd   m0, m4, m3
84cabdff1aSopenharmony_ci    mulpd   m1, m5, m3
85cabdff1aSopenharmony_ci    mulpd   m2, m6, m3
86cabdff1aSopenharmony_ci    mulpd   m3, m3, m7
87cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(2,0), m0
88cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(2,1), m1
89cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(2,2), m2
90cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(2,3), m3
91cabdff1aSopenharmony_ci    mova    m3, [varq + jq*8 + 32]
92cabdff1aSopenharmony_ci    add covarq, 32
93cabdff1aSopenharmony_ci    add     jq, 4
94cabdff1aSopenharmony_ci    cmp     jd, -2
95cabdff1aSopenharmony_ci    jle .loop4x4
96cabdff1aSopenharmony_ci.skip4x4:
97cabdff1aSopenharmony_ci    test    jd, jd
98cabdff1aSopenharmony_ci    jg .skip2x4
99cabdff1aSopenharmony_ci    mulpd   m4, m3
100cabdff1aSopenharmony_ci    mulpd   m5, m3
101cabdff1aSopenharmony_ci    mulpd   m6, m3
102cabdff1aSopenharmony_ci    mulpd   m7, m3
103cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,0), m4
104cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,1), m5
105cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,2), m6
106cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,3), m7
107cabdff1aSopenharmony_ci.skip2x4:
108cabdff1aSopenharmony_ci    add     iq, 4
109cabdff1aSopenharmony_ci    add covar2q, 4*COVAR_STRIDE+32
110cabdff1aSopenharmony_ci    cmp     id, -2
111cabdff1aSopenharmony_ci    jle .loopi
112cabdff1aSopenharmony_ci    test    id, id
113cabdff1aSopenharmony_ci    jg .ret
114cabdff1aSopenharmony_ci    mov     jq, iq
115cabdff1aSopenharmony_ci    %define covarq covar2q
116cabdff1aSopenharmony_ci.loop2x1:
117cabdff1aSopenharmony_ci    movsd   m0, [varq + iq*8]
118cabdff1aSopenharmony_ci    movlhps m0, m0
119cabdff1aSopenharmony_ci    mulpd   m0, [varq + jq*8]
120cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(0,0), m0
121cabdff1aSopenharmony_ci    inc     iq
122cabdff1aSopenharmony_ci    add covarq, COVAR_STRIDE
123cabdff1aSopenharmony_ci    test    id, id
124cabdff1aSopenharmony_ci    jle .loop2x1
125cabdff1aSopenharmony_ci.ret:
126cabdff1aSopenharmony_ci    REP_RET
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci%macro UPDATE_LLS 0
129cabdff1aSopenharmony_cicglobal update_lls, 3,6,8, ctx, var, count, i, j, count2
130cabdff1aSopenharmony_ci    %define covarq ctxq
131cabdff1aSopenharmony_ci    mov  countd, [ctxq + LLSModel.indep_count]
132cabdff1aSopenharmony_ci    lea count2d, [countq-2]
133cabdff1aSopenharmony_ci    xor     id, id
134cabdff1aSopenharmony_ci.loopi:
135cabdff1aSopenharmony_ci    ; Compute all 10 pairwise products of a 4x4 block that lies on the diagonal
136cabdff1aSopenharmony_ci    mova    ymm1, [varq + iq*8]
137cabdff1aSopenharmony_ci    vbroadcastsd ymm4, [varq + iq*8]
138cabdff1aSopenharmony_ci    vbroadcastsd ymm5, [varq + iq*8 + 8]
139cabdff1aSopenharmony_ci    vbroadcastsd ymm6, [varq + iq*8 + 16]
140cabdff1aSopenharmony_ci    vbroadcastsd ymm7, [varq + iq*8 + 24]
141cabdff1aSopenharmony_ci    vextractf128 xmm3, ymm1, 1
142cabdff1aSopenharmony_ci%if cpuflag(fma3)
143cabdff1aSopenharmony_ci    mova ymm0, COVAR(iq  ,0)
144cabdff1aSopenharmony_ci    mova xmm2, COVAR(iq+2,2)
145cabdff1aSopenharmony_ci    fmaddpd ymm0, ymm1, ymm4, ymm0
146cabdff1aSopenharmony_ci    fmaddpd xmm2, xmm3, xmm6, xmm2
147cabdff1aSopenharmony_ci    fmaddpd ymm1, ymm5, ymm1, COVAR(iq  ,1)
148cabdff1aSopenharmony_ci    fmaddpd xmm3, xmm7, xmm3, COVAR(iq+2,3)
149cabdff1aSopenharmony_ci    mova COVAR(iq  ,0), ymm0
150cabdff1aSopenharmony_ci    mova COVAR(iq  ,1), ymm1
151cabdff1aSopenharmony_ci    mova COVAR(iq+2,2), xmm2
152cabdff1aSopenharmony_ci    mova COVAR(iq+2,3), xmm3
153cabdff1aSopenharmony_ci%else
154cabdff1aSopenharmony_ci    vmulpd  ymm0, ymm1, ymm4
155cabdff1aSopenharmony_ci    vmulpd  ymm1, ymm1, ymm5
156cabdff1aSopenharmony_ci    vmulpd  xmm2, xmm3, xmm6
157cabdff1aSopenharmony_ci    vmulpd  xmm3, xmm3, xmm7
158cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(iq  ,0), ymm0
159cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(iq  ,1), ymm1
160cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(iq+2,2), xmm2
161cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(iq+2,3), xmm3
162cabdff1aSopenharmony_ci%endif ; cpuflag(fma3)
163cabdff1aSopenharmony_ci    lea     jd, [iq + 4]
164cabdff1aSopenharmony_ci    cmp     jd, count2d
165cabdff1aSopenharmony_ci    jg .skip4x4
166cabdff1aSopenharmony_ci.loop4x4:
167cabdff1aSopenharmony_ci    ; Compute all 16 pairwise products of a 4x4 block
168cabdff1aSopenharmony_ci    mova    ymm3, [varq + jq*8]
169cabdff1aSopenharmony_ci%if cpuflag(fma3)
170cabdff1aSopenharmony_ci    mova ymm0, COVAR(jq, 0)
171cabdff1aSopenharmony_ci    mova ymm1, COVAR(jq, 1)
172cabdff1aSopenharmony_ci    mova ymm2, COVAR(jq, 2)
173cabdff1aSopenharmony_ci    fmaddpd ymm0, ymm3, ymm4, ymm0
174cabdff1aSopenharmony_ci    fmaddpd ymm1, ymm3, ymm5, ymm1
175cabdff1aSopenharmony_ci    fmaddpd ymm2, ymm3, ymm6, ymm2
176cabdff1aSopenharmony_ci    fmaddpd ymm3, ymm7, ymm3, COVAR(jq,3)
177cabdff1aSopenharmony_ci    mova COVAR(jq, 0), ymm0
178cabdff1aSopenharmony_ci    mova COVAR(jq, 1), ymm1
179cabdff1aSopenharmony_ci    mova COVAR(jq, 2), ymm2
180cabdff1aSopenharmony_ci    mova COVAR(jq, 3), ymm3
181cabdff1aSopenharmony_ci%else
182cabdff1aSopenharmony_ci    vmulpd  ymm0, ymm3, ymm4
183cabdff1aSopenharmony_ci    vmulpd  ymm1, ymm3, ymm5
184cabdff1aSopenharmony_ci    vmulpd  ymm2, ymm3, ymm6
185cabdff1aSopenharmony_ci    vmulpd  ymm3, ymm3, ymm7
186cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,0), ymm0
187cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,1), ymm1
188cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,2), ymm2
189cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,3), ymm3
190cabdff1aSopenharmony_ci%endif ; cpuflag(fma3)
191cabdff1aSopenharmony_ci    add     jd, 4
192cabdff1aSopenharmony_ci    cmp     jd, count2d
193cabdff1aSopenharmony_ci    jle .loop4x4
194cabdff1aSopenharmony_ci.skip4x4:
195cabdff1aSopenharmony_ci    cmp     jd, countd
196cabdff1aSopenharmony_ci    jg .skip2x4
197cabdff1aSopenharmony_ci    mova    xmm3, [varq + jq*8]
198cabdff1aSopenharmony_ci%if cpuflag(fma3)
199cabdff1aSopenharmony_ci    mova xmm0, COVAR(jq, 0)
200cabdff1aSopenharmony_ci    mova xmm1, COVAR(jq, 1)
201cabdff1aSopenharmony_ci    mova xmm2, COVAR(jq, 2)
202cabdff1aSopenharmony_ci    fmaddpd xmm0, xmm3, xmm4, xmm0
203cabdff1aSopenharmony_ci    fmaddpd xmm1, xmm3, xmm5, xmm1
204cabdff1aSopenharmony_ci    fmaddpd xmm2, xmm3, xmm6, xmm2
205cabdff1aSopenharmony_ci    fmaddpd xmm3, xmm7, xmm3, COVAR(jq,3)
206cabdff1aSopenharmony_ci    mova COVAR(jq, 0), xmm0
207cabdff1aSopenharmony_ci    mova COVAR(jq, 1), xmm1
208cabdff1aSopenharmony_ci    mova COVAR(jq, 2), xmm2
209cabdff1aSopenharmony_ci    mova COVAR(jq, 3), xmm3
210cabdff1aSopenharmony_ci%else
211cabdff1aSopenharmony_ci    vmulpd  xmm0, xmm3, xmm4
212cabdff1aSopenharmony_ci    vmulpd  xmm1, xmm3, xmm5
213cabdff1aSopenharmony_ci    vmulpd  xmm2, xmm3, xmm6
214cabdff1aSopenharmony_ci    vmulpd  xmm3, xmm3, xmm7
215cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,0), xmm0
216cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,1), xmm1
217cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,2), xmm2
218cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,3), xmm3
219cabdff1aSopenharmony_ci%endif ; cpuflag(fma3)
220cabdff1aSopenharmony_ci.skip2x4:
221cabdff1aSopenharmony_ci    add     id, 4
222cabdff1aSopenharmony_ci    add covarq, 4*COVAR_STRIDE
223cabdff1aSopenharmony_ci    cmp     id, count2d
224cabdff1aSopenharmony_ci    jle .loopi
225cabdff1aSopenharmony_ci    cmp     id, countd
226cabdff1aSopenharmony_ci    jg .ret
227cabdff1aSopenharmony_ci    mov     jd, id
228cabdff1aSopenharmony_ci.loop2x1:
229cabdff1aSopenharmony_ci    vmovddup xmm0, [varq + iq*8]
230cabdff1aSopenharmony_ci%if cpuflag(fma3)
231cabdff1aSopenharmony_ci    mova xmm1, [varq + jq*8]
232cabdff1aSopenharmony_ci    fmaddpd xmm0, xmm1, xmm0, COVAR(jq,0)
233cabdff1aSopenharmony_ci    mova COVAR(jq,0), xmm0
234cabdff1aSopenharmony_ci%else
235cabdff1aSopenharmony_ci    vmulpd   xmm0, [varq + jq*8]
236cabdff1aSopenharmony_ci    ADDPD_MEM COVAR(jq,0), xmm0
237cabdff1aSopenharmony_ci%endif ; cpuflag(fma3)
238cabdff1aSopenharmony_ci    inc     id
239cabdff1aSopenharmony_ci    add covarq, COVAR_STRIDE
240cabdff1aSopenharmony_ci    cmp     id, countd
241cabdff1aSopenharmony_ci    jle .loop2x1
242cabdff1aSopenharmony_ci.ret:
243cabdff1aSopenharmony_ci    REP_RET
244cabdff1aSopenharmony_ci%endmacro ; UPDATE_LLS
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_ci%if HAVE_AVX_EXTERNAL
247cabdff1aSopenharmony_ciINIT_YMM avx
248cabdff1aSopenharmony_ciUPDATE_LLS
249cabdff1aSopenharmony_ci%endif
250cabdff1aSopenharmony_ci%if HAVE_FMA3_EXTERNAL
251cabdff1aSopenharmony_ciINIT_YMM fma3
252cabdff1aSopenharmony_ciUPDATE_LLS
253cabdff1aSopenharmony_ci%endif
254cabdff1aSopenharmony_ci
255cabdff1aSopenharmony_ciINIT_XMM sse2
256cabdff1aSopenharmony_cicglobal evaluate_lls, 3,4,2, ctx, var, order, i
257cabdff1aSopenharmony_ci    ; This function is often called on the same buffer as update_lls, but with
258cabdff1aSopenharmony_ci    ; an offset. They can't both be aligned.
259cabdff1aSopenharmony_ci    ; Load halves rather than movu to avoid store-forwarding stalls, since the
260cabdff1aSopenharmony_ci    ; input was initialized immediately prior to this function using scalar math.
261cabdff1aSopenharmony_ci    %define coefsq ctxq
262cabdff1aSopenharmony_ci    mov     id, orderd
263cabdff1aSopenharmony_ci    imul    orderd, MAX_VARS
264cabdff1aSopenharmony_ci    lea     coefsq, [ctxq + LLSModel.coeff + orderq*8]
265cabdff1aSopenharmony_ci    movsd   m0, [varq]
266cabdff1aSopenharmony_ci    movhpd  m0, [varq + 8]
267cabdff1aSopenharmony_ci    mulpd   m0, [coefsq]
268cabdff1aSopenharmony_ci    lea coefsq, [coefsq + iq*8]
269cabdff1aSopenharmony_ci    lea   varq, [varq + iq*8]
270cabdff1aSopenharmony_ci    neg     iq
271cabdff1aSopenharmony_ci    add     iq, 2
272cabdff1aSopenharmony_ci.loop:
273cabdff1aSopenharmony_ci    movsd   m1, [varq + iq*8]
274cabdff1aSopenharmony_ci    movhpd  m1, [varq + iq*8 + 8]
275cabdff1aSopenharmony_ci    mulpd   m1, [coefsq + iq*8]
276cabdff1aSopenharmony_ci    addpd   m0, m1
277cabdff1aSopenharmony_ci    add     iq, 2
278cabdff1aSopenharmony_ci    jl .loop
279cabdff1aSopenharmony_ci    jg .skip1
280cabdff1aSopenharmony_ci    movsd   m1, [varq + iq*8]
281cabdff1aSopenharmony_ci    mulsd   m1, [coefsq + iq*8]
282cabdff1aSopenharmony_ci    addpd   m0, m1
283cabdff1aSopenharmony_ci.skip1:
284cabdff1aSopenharmony_ci    movhlps m1, m0
285cabdff1aSopenharmony_ci    addsd   m0, m1
286cabdff1aSopenharmony_ci%if ARCH_X86_32
287cabdff1aSopenharmony_ci    movsd  r0m, m0
288cabdff1aSopenharmony_ci    fld   qword r0m
289cabdff1aSopenharmony_ci%endif
290cabdff1aSopenharmony_ci    RET
291