soup up, fix bugs, replace PSHUFW with pre-Katmai-friendly PSRLQ mm,32
[flac.git] / src / libFLAC / i386 / fixed_asm.nasm
1 ; libFLAC - Free Lossless Audio Codec library
2 ; Copyright (C) 2001  Josh Coalson
3 ;
4 ; This library is free software; you can redistribute it and/or
5 ; modify it under the terms of the GNU Library General Public
6 ; License as published by the Free Software Foundation; either
7 ; version 2 of the License, or (at your option) any later version.
8 ;
9 ; This library is distributed in the hope that it will be useful,
10 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ; Library General Public License for more details.
13 ;
14 ; You should have received a copy of the GNU Library General Public
15 ; License along with this library; if not, write to the
16 ; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 ; Boston, MA  02111-1307, USA.
18
19 %include "nasm.h"
20
21         data_section
22
23 cglobal FLAC__fixed_compute_best_predictor
24
25         code_section
26
27 ; **********************************************************************
28 ;
29 ; unsigned FLAC__fixed_compute_best_predictor(const int32 data[], unsigned data_len, real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
30 ; {
31 ;       int32 last_error_0 = data[-1];
32 ;       int32 last_error_1 = data[-1] - data[-2];
33 ;       int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
34 ;       int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
35 ;       int32 error, save;
36 ;       uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
37 ;       unsigned i, order;
38 ;
39 ;       for(i = 0; i < data_len; i++) {
40 ;               error  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
41 ;               error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
42 ;               error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
43 ;               error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
44 ;               error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
45 ;       }
46 ;
47 ;       if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
48 ;               order = 0;
49 ;       else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
50 ;               order = 1;
51 ;       else if(total_error_2 < min(total_error_3, total_error_4))
52 ;               order = 2;
53 ;       else if(total_error_3 < total_error_4)
54 ;               order = 3;
55 ;       else
56 ;               order = 4;
57 ;
58 ;       residual_bits_per_sample[0] = (real)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (real)total_error_0  / (real) data_len) / M_LN2 : 0.0);
59 ;       residual_bits_per_sample[1] = (real)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (real)total_error_1  / (real) data_len) / M_LN2 : 0.0);
60 ;       residual_bits_per_sample[2] = (real)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (real)total_error_2  / (real) data_len) / M_LN2 : 0.0);
61 ;       residual_bits_per_sample[3] = (real)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (real)total_error_3  / (real) data_len) / M_LN2 : 0.0);
62 ;       residual_bits_per_sample[4] = (real)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (real)total_error_4  / (real) data_len) / M_LN2 : 0.0);
63 ;
64 ;       return order;
65 ; }
66 ;@@@ NOTE: not tested yet!
67 FLAC__fixed_compute_best_predictor_asm:
68
69         ; esp + 28 == data[]
70         ; esp + 32 == data_len
71         ; esp + 36 == residual_bits_per_sample[]
72
73         push    ebp
74         push    ebx
75         push    esi
76         push    edi
77         sub     esp, byte 8                     ; [esp + 0] == temp space for loading uint64s to FPU regs
78
79         ; eax == error
80         ; ebx == &data[i]
81         ; mm0 == total_error_1:total_error_0
82         ; mm1 == total_error_3:total_error_2
83         ; mm2 == 0:total_error_4
84         ; mm3/4 == 0:unpackarea
85         ; mm5 == abs(error_1):abs(error_0)
86         ; mm5 == abs(error_3):abs(error_2)
87         ; mm6 == last_error_1:last_error_0
88         ; mm7 == last_error_3:last_error_2
89
90         pxor    mm0, mm0                        ; total_error_1 = total_error_0 = 0
91         pxor    mm1, mm1                        ; total_error_3 = total_error_2 = 0
92         pxor    mm2, mm2                        ; total_error_4 = 0
93         mov     ebx, [esp + 28]                 ; ebx = data[]
94         mov     ecx, [ebx - 4]                  ; ecx == data[-1]  last_error_0 = data[-1]
95         mov     eax, [ebx - 8]                  ; eax == data[-2]
96         mov     ebp, [ebx - 16]                 ; ebp == data[-4]
97         mov     ebx, [ebx - 12]                 ; ebx == data[-3]
98         mov     edx, ecx
99         sub     edx, eax                        ; last_error_1 = data[-1] - data[-2]
100         mov     esi, edx
101         sub     esi, eax
102         add     esi, ebx                        ; last_error_2 = last_error_1 - (data[-2] - data[-3])
103         shl     ebx, 1
104         mov     edi, esi
105         sub     edi, eax
106         add     edi, ebx
107         sub     edi, ebp                        ; last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
108         mov     ebx, [esp + 28]                 ; ebx = data[]
109         movd    mm6, ecx                        ; mm6 = 0:last_error_0
110         movd    mm3, edx                        ; mm3 = 0:last_error_1
111         movd    mm7, esi                        ; mm7 = 0:last_error_2
112         movd    mm4, edi                        ; mm4 = 0:last_error_3
113         punpckldq       mm6, mm3                ; mm6 = last_error_1:last_error_0
114         punpckldq       mm7, mm4                ; mm7 = last_error_3:last_error_2
115         mov     ecx, [esp + 32]                 ; ecx = data_len
116
117         ;       for(i = 0; i < data_len; i++) {
118         ;               error_0  = data[i]     ;                      save = error_0; total_error_0 += local_abs(error_0);
119         ;               error_1 -= last_error_0; last_error_0 = save; save = error_1; total_error_1 += local_abs(error_1);
120         ;               error_2 -= last_error_1; last_error_1 = save; save = error_2; total_error_2 += local_abs(error_2);
121         ;               error_3 -= last_error_2; last_error_2 = save; save = error_3; total_error_3 += local_abs(error_3);
122         ;               error_4 -= last_error_3; last_error_3 = save;                 total_error_4 += local_abs(error_4);
123         ;       }
124 .loop:
125         mov     eax, [ebx]                      ; eax = error_0 = data[i]
126         add     ebx, 4
127         mov     edi, eax                        ; edi == save = error_0
128         mov     edx, eax                        ; edx = error_0
129         neg     edx                             ; edx = -error_0
130         cmovns  eax, edx                        ; eax = abs(error_0)
131         movd    mm5, eax                        ; mm5 = 0:abs(error_0)
132         movd    edx, mm6                        ; edx = last_error_0
133         mov     eax, edi                        ; eax = error(error_0)
134         movaps  mm3, mm6                        ; mm3 = last_error_1:last_error_0
135         psrlq   mm3, 32                         ; mm3 = 0:last_error_1
136         movd    mm6, edi                        ; mm6 = 0:last_error_0(=save)
137         punpckldq       mm6, mm3                ; mm6 = last_error_1:last_error_0(=save)
138         sub     eax, edx                        ; error -= last_error_0
139         mov     edi, eax                        ; edi == save = error_1
140         mov     edx, eax                        ; edx = error_1
141         neg     edx                             ; edx = -error_1
142         cmovns  eax, edx                        ; eax = abs(error_1)
143         movd    mm4, eax                        ; mm4 = 0:abs(error_1)
144         punpckldq       mm5, mm4                ; mm5 = abs(error_1):abs(error_0)
145         movaps  mm3, mm6                        ; mm3 = last_error_1:last_error_0
146         psrlq   mm3, 32                         ; mm3 = 0:last_error_1
147         movd    edx, mm3                        ; edx = last_error_1
148         mov     eax, edi                        ; eax = error(error_1)
149         movd    mm4, edi                        ; mm4 = 0:save
150         punpckldq       mm6, mm4                ; mm6 = last_error_1(=save):last_error_0
151         sub     eax, edx                        ; error -= last_error_1
152         mov     edi, eax                        ; edi == save = error_2
153         mov     edx, eax                        ; edx = error_2
154         paddd   mm0, mm5                        ; [CR] total_error_1 += abs(error_1) ; total_error_0 += abs(error_0)
155         neg     edx                             ; edx = -error_2
156         cmovns  eax, edx                        ; eax = abs(error_2)
157         movd    mm5, eax                        ; mm5 = 0:abs(error_2)
158         movd    edx, mm7                        ; edx = last_error_2
159         mov     eax, edi                        ; eax = error(error_2)
160         movaps  mm3, mm7                        ; mm3 = last_error_3:last_error_2
161         psrlq   mm3, 32                         ; mm3 = 0:last_error_3
162         movd    mm7, edi                        ; mm7 = 0:last_error_2(=save)
163         punpckldq       mm7, mm3                ; mm7 = last_error_3:last_error_2
164         sub     eax, edx                        ; error -= last_error_2
165         mov     edi, eax                        ; edi == save = error_3
166         mov     edx, eax                        ; edx = error_3
167         neg     edx                             ; edx = -error_3
168         cmovns  eax, edx                        ; eax = abs(error_3)
169         movd    mm4, eax                        ; mm4 = 0:abs(error_3)
170         punpckldq       mm5, mm4                ; mm5 = abs(error_3):abs(error_2)
171         movaps  mm3, mm7
172         psrlq   mm3, 32                         ; mm3 = 0:last_error_3
173         movd    edx, mm3                        ; edx = last_error_3
174         mov     eax, edi                        ; eax = error(error_3)
175         movd    mm4, edi                        ; mm4 = 0:save
176         punpckldq       mm7, mm4                ; mm7 = last_error_3(=save):last_error_2
177         sub     eax, edx                        ; error -= last_error_3
178         mov     edx, eax                        ; edx = error_4
179         paddd   mm1, mm5                        ; [CR] total_error_3 += abs(error_3) ; total_error_2 += abs(error_2)
180         neg     edx                             ; edx = -error_4
181         cmovns  eax, edx                        ; eax = abs(error_4)
182         movd    mm5, eax                        ; mm5 = 0:abs(error_4)
183         paddd   mm2, mm5                        ; total_error_4 += abs(error_4)
184         dec     ecx
185         jnz     near .loop
186
187 ;       if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
188 ;               order = 0;
189 ;       else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
190 ;               order = 1;
191 ;       else if(total_error_2 < min(total_error_3, total_error_4))
192 ;               order = 2;
193 ;       else if(total_error_3 < total_error_4)
194 ;               order = 3;
195 ;       else
196 ;               order = 4;
197         movd    edi, mm2                        ; edi = total_error_4
198         movaps  mm4, mm1                        ; mm4 = total_error_3:total_error_2
199         psrlq   mm4, 32                         ; mm4 = 0:total_error_3
200         movd    edx, mm1                        ; edx = total_error_2
201         movd    esi, mm4                        ; esi = total_error_3
202         movaps  mm3, mm0                        ; mm3 = total_error_1:total_error_0
203         psrlq   mm3, 32                         ; mm3 = 0:total_error_1
204         movd    ebx, mm0                        ; ebx = total_error_0
205         movd    ecx, mm3                        ; ecx = total_error_1
206         emms
207         mov     eax, ebx                        ; eax = total_error_0
208         cmp     ecx, ebx
209         cmovb   eax, ecx                        ; eax = min(total_error_0, total_error_1)
210         cmp     edx, eax
211         cmovb   eax, edx                        ; eax = min(total_error_0, total_error_1, total_error_2)
212         cmp     esi, eax
213         cmovb   eax, esi                        ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3)
214         cmp     edi, eax
215         cmovb   eax, edi                        ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3, total_error_4)
216
217         cmp     eax, ebx
218         jne     .not_order_0
219         xor     ebp, ebp
220         jmp     short .got_order
221 .not_order_0:
222         cmp     eax, ecx
223         jne     .not_order_1
224         mov     ebp, 1
225         jmp     short .got_order
226 .not_order_1:
227         cmp     eax, edx
228         jne     .not_order_2
229         mov     ebp, 2
230         jmp     short .got_order
231 .not_order_2:
232         cmp     eax, esi
233         jne     .not_order_3
234         mov     ebp, 3
235         jmp     short .got_order
236 .not_order_3:
237         mov     ebp, 4
238 .got_order:
239         ;       residual_bits_per_sample[0] = (real)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (real)total_error_0  / (real) data_len) / M_LN2 : 0.0);
240         ;       residual_bits_per_sample[1] = (real)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (real)total_error_1  / (real) data_len) / M_LN2 : 0.0);
241         ;       residual_bits_per_sample[2] = (real)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (real)total_error_2  / (real) data_len) / M_LN2 : 0.0);
242         ;       residual_bits_per_sample[3] = (real)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (real)total_error_3  / (real) data_len) / M_LN2 : 0.0);
243         ;       residual_bits_per_sample[4] = (real)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (real)total_error_4  / (real) data_len) / M_LN2 : 0.0);
244         xor     eax, eax
245         cmp     eax, [esp + 32]
246         je      near .data_len_is_0
247         fild    dword [esp + 32]                ; ST = data_len (NOTE: assumes data_len is <2gigs)
248 .rbps_0:
249         test    ebx, ebx
250         jz      .total_error_0_is_0
251         fld1                                    ; ST = 1.0 data_len
252         mov     [esp], ebx
253         mov     [esp + 4], eax                  ; [esp + 0] = (uint64)total_error_0
254         mov     ebx, [esp + 36]
255         fild    qword [esp]                     ; ST = total_error_0 1.0 data_len
256         fdiv    st2                             ; ST = total_error_0/data_len 1.0 data_len
257         fldln2                                  ; ST = ln2 total_error_0/data_len 1.0 data_len
258         fmulp   st1                             ; ST = ln2*total_error_0/data_len 1.0 data_len
259         fyl2x                                   ; ST = log2(ln2*total_error_0/data_len) data_len
260         fstp    dword [ebx]                     ; residual_bits_per_sample[0] = log2(ln2*total_error_0/data_len)   ST = data_len
261         jmp     short .rbps_1
262 .total_error_0_is_0:
263         mov     ebx, [esp + 36]
264         mov     [ebx], eax                      ; residual_bits_per_sample[0] = 0.0
265 .rbps_1:
266         test    ecx, ecx
267         jz      .total_error_1_is_0
268         fld1                                    ; ST = 1.0 data_len
269         mov     [esp], ecx
270         mov     [esp + 4], eax                  ; [esp + 0] = (uint64)total_error_1
271         fild    qword [esp]                     ; ST = total_error_1 1.0 data_len
272         fdiv    st2                             ; ST = total_error_1/data_len 1.0 data_len
273         fldln2                                  ; ST = ln2 total_error_1/data_len 1.0 data_len
274         fmulp   st1                             ; ST = ln2*total_error_1/data_len 1.0 data_len
275         fyl2x                                   ; ST = log2(ln2*total_error_1/data_len) data_len
276         fstp    dword [ebx + 4]                 ; residual_bits_per_sample[1] = log2(ln2*total_error_1/data_len)   ST = data_len
277         jmp     short .rbps_2
278 .total_error_1_is_0:
279         mov     [ebx + 4], eax                  ; residual_bits_per_sample[1] = 0.0
280 .rbps_2:
281         test    edx, edx
282         jz      .total_error_2_is_0
283         fld1                                    ; ST = 1.0 data_len
284         mov     [esp], edx
285         mov     [esp + 4], eax                  ; [esp + 0] = (uint64)total_error_2
286         fild    qword [esp]                     ; ST = total_error_2 1.0 data_len
287         fdiv    st2                             ; ST = total_error_2/data_len 1.0 data_len
288         fldln2                                  ; ST = ln2 total_error_2/data_len 1.0 data_len
289         fmulp   st1                             ; ST = ln2*total_error_2/data_len 1.0 data_len
290         fyl2x                                   ; ST = log2(ln2*total_error_2/data_len) data_len
291         fstp    dword [ebx + 8]                 ; residual_bits_per_sample[2] = log2(ln2*total_error_2/data_len)   ST = data_len
292         jmp     short .rbps_3
293 .total_error_2_is_0:
294         mov     [ebx + 8], eax                  ; residual_bits_per_sample[2] = 0.0
295 .rbps_3:
296         test    esi, esi
297         jz      .total_error_3_is_0
298         fld1                                    ; ST = 1.0 data_len
299         mov     [esp], esi
300         mov     [esp + 4], eax                  ; [esp + 0] = (uint64)total_error_3
301         fild    qword [esp]                     ; ST = total_error_3 1.0 data_len
302         fdiv    st2                             ; ST = total_error_3/data_len 1.0 data_len
303         fldln2                                  ; ST = ln2 total_error_3/data_len 1.0 data_len
304         fmulp   st1                             ; ST = ln2*total_error_3/data_len 1.0 data_len
305         fyl2x                                   ; ST = log2(ln2*total_error_3/data_len) data_len
306         fstp    dword [ebx + 12]                ; residual_bits_per_sample[3] = log2(ln2*total_error_3/data_len)   ST = data_len
307         jmp     short .rbps_4
308 .total_error_3_is_0:
309         mov     [ebx + 12], eax                 ; residual_bits_per_sample[3] = 0.0
310 .rbps_4:
311         test    edi, edi
312         jz      .total_error_4_is_0
313         fld1                                    ; ST = 1.0 data_len
314         mov     [esp], edi
315         mov     [esp + 4], eax                  ; [esp + 0] = (uint64)total_error_4
316         fild    qword [esp]                     ; ST = total_error_4 1.0 data_len
317         fdiv    st2                             ; ST = total_error_4/data_len 1.0 data_len
318         fldln2                                  ; ST = ln2 total_error_4/data_len 1.0 data_len
319         fmulp   st1                             ; ST = ln2*total_error_4/data_len 1.0 data_len
320         fyl2x                                   ; ST = log2(ln2*total_error_4/data_len) data_len
321         fstp    dword [ebx + 16]                ; residual_bits_per_sample[4] = log2(ln2*total_error_4/data_len)   ST = data_len
322         jmp     short .rbps_end
323 .total_error_4_is_0:
324         mov     [ebx + 16], eax                 ; residual_bits_per_sample[4] = 0.0
325 .rbps_end:
326         fstp    st0                             ; ST = [empty]
327         jmp     short .end
328 .data_len_is_0:
329         ; data_len == 0, so residual_bits_per_sample[*] = 0.0
330         mov     ecx, 5                          ; eax still == 0, ecx = # of dwords of 0 to store
331         mov     edi, [esp + 36]
332         rep stosd
333
334 .end:
335         mov     eax, ebp                        ; return order
336         add     esp, byte 8
337         pop     edi
338         pop     esi
339         pop     ebx
340         pop     ebp
341         ret
342
343 end