minor naming convention changes
[flac.git] / src / libFLAC / ia32 / 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_asm_ia32_mmx_cmov
24
25         code_section
26
27 ; **********************************************************************
28 ;
29 ; unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
30 ; {
31 ;       FLAC__int32 last_error_0 = data[-1];
32 ;       FLAC__int32 last_error_1 = data[-1] - data[-2];
33 ;       FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
34 ;       FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
35 ;       FLAC__int32 error, save;
36 ;       FLAC__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] = (FLAC__real)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
59 ;       residual_bits_per_sample[1] = (FLAC__real)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
60 ;       residual_bits_per_sample[2] = (FLAC__real)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
61 ;       residual_bits_per_sample[3] = (FLAC__real)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
62 ;       residual_bits_per_sample[4] = (FLAC__real)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
63 ;
64 ;       return order;
65 ; }
66         ALIGN 16
67 cident FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov
68
69         ; esp + 36 == data[]
70         ; esp + 40 == data_len
71         ; esp + 44 == residual_bits_per_sample[]
72
73         push    ebp
74         push    ebx
75         push    esi
76         push    edi
77         sub     esp, byte 16
78         ; qword [esp] == temp space for loading FLAC__uint64s to FPU regs
79         ; dword [esp] == last_error_0
80         ; dword [esp + 4] == last_error_1
81         ; dword [esp + 8] == last_error_2
82         ; dword [esp + 12] == last_error_3
83
84         ; eax == error
85         ; ebx == &data[i]
86         ; ecx == loop counter (i)
87         ; edx == temp
88         ; edi == save
89         ; ebp == order
90         ; mm0 == total_error_1:total_error_0
91         ; mm1 == total_error_3:total_error_2
92         ; mm2 == 0:total_error_4
93         ; mm3/4 == 0:unpackarea
94         ; mm5 == abs(error_1):abs(error_0)
95         ; mm5 == abs(error_3):abs(error_2)
96
97         pxor    mm0, mm0                        ; total_error_1 = total_error_0 = 0
98         pxor    mm1, mm1                        ; total_error_3 = total_error_2 = 0
99         pxor    mm2, mm2                        ; total_error_4 = 0
100         mov     ebx, [esp + 36]                 ; ebx = data[]
101         mov     ecx, [ebx - 4]                  ; ecx == data[-1]  last_error_0 = data[-1]
102         mov     eax, [ebx - 8]                  ; eax == data[-2]
103         mov     ebp, [ebx - 16]                 ; ebp == data[-4]
104         mov     ebx, [ebx - 12]                 ; ebx == data[-3]
105         mov     edx, ecx
106         sub     edx, eax                        ; last_error_1 = data[-1] - data[-2]
107         mov     esi, edx
108         sub     esi, eax
109         add     esi, ebx                        ; last_error_2 = last_error_1 - (data[-2] - data[-3])
110         shl     ebx, 1
111         mov     edi, esi
112         sub     edi, eax
113         add     edi, ebx
114         sub     edi, ebp                        ; last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
115         mov     ebx, [esp + 36]                 ; ebx = data[]
116         mov     [esp], ecx                      ; [esp] = last_error_0
117         mov     [esp + 4], edx                  ; [esp + 4] = last_error_1
118         mov     [esp + 8], esi                  ; [esp + 8] = last_error_2
119         mov     [esp + 12], edi                 ; [esp + 12] = last_error_3
120         mov     ecx, [esp + 40]                 ; ecx = data_len
121
122         ;       for(i = 0; i < data_len; i++) {
123         ;               error_0  = data[i]     ;                      save = error_0; total_error_0 += local_abs(error_0);
124         ;               error_1 -= last_error_0; last_error_0 = save; save = error_1; total_error_1 += local_abs(error_1);
125         ;               error_2 -= last_error_1; last_error_1 = save; save = error_2; total_error_2 += local_abs(error_2);
126         ;               error_3 -= last_error_2; last_error_2 = save; save = error_3; total_error_3 += local_abs(error_3);
127         ;               error_4 -= last_error_3; last_error_3 = save;                 total_error_4 += local_abs(error_4);
128         ;       }
129         ALIGN 16
130 .loop:
131         mov     eax, [ebx]                      ; eax = error_0 = data[i]
132         add     ebx, 4
133         mov     edi, eax                        ; edi == save = error_0
134         mov     edx, eax                        ; edx = error_0
135         neg     edx                             ; edx = -error_0
136         cmovns  eax, edx                        ; eax = abs(error_0)
137         movd    mm5, eax                        ; mm5 = 0:abs(error_0)
138         mov     edx, [esp]                      ; edx = last_error_0
139         mov     eax, edi                        ; eax = error(error_0)
140         mov     [esp], edi                      ; [esp] == last_error_0 = save
141         sub     eax, edx                        ; error -= last_error_0
142         mov     edi, eax                        ; edi == save = error_1
143         mov     edx, eax                        ; edx = error_1
144         neg     edx                             ; edx = -error_1
145         cmovns  eax, edx                        ; eax = abs(error_1)
146         movd    mm4, eax                        ; mm4 = 0:abs(error_1)
147         punpckldq       mm5, mm4                ; mm5 = abs(error_1):abs(error_0)
148         mov     edx, [esp + 4]                  ; edx = last_error_1
149         mov     eax, edi                        ; eax = error(error_1)
150         mov     [esp + 4], edi                  ; [esp + 4] == last_error_1 = save
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         mov     edx, [esp + 8]                  ; edx = last_error_2
159         mov     eax, edi                        ; eax = error(error_2)
160         mov     [esp + 8], edi                  ; [esp + 8] == last_error_2 = save
161         sub     eax, edx                        ; error -= last_error_2
162         mov     edi, eax                        ; edi == save = error_3
163         mov     edx, eax                        ; edx = error_3
164         neg     edx                             ; edx = -error_3
165         cmovns  eax, edx                        ; eax = abs(error_3)
166         movd    mm4, eax                        ; mm4 = 0:abs(error_3)
167         punpckldq       mm5, mm4                ; mm5 = abs(error_3):abs(error_2)
168         mov     edx, [esp + 12]                 ; edx = last_error_3
169         mov     eax, edi                        ; eax = error(error_3)
170         mov     [esp + 12], edi                 ; [esp + 12] == last_error_3 = save
171         sub     eax, edx                        ; error -= last_error_3
172         mov     edx, eax                        ; edx = error_4
173         paddd   mm1, mm5                        ; [CR] total_error_3 += abs(error_3) ; total_error_2 += abs(error_2)
174         neg     edx                             ; edx = -error_4
175         cmovns  eax, edx                        ; eax = abs(error_4)
176         movd    mm5, eax                        ; mm5 = 0:abs(error_4)
177         paddd   mm2, mm5                        ; total_error_4 += abs(error_4)
178         dec     ecx
179         jnz     near .loop
180
181 ;       if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
182 ;               order = 0;
183 ;       else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
184 ;               order = 1;
185 ;       else if(total_error_2 < min(total_error_3, total_error_4))
186 ;               order = 2;
187 ;       else if(total_error_3 < total_error_4)
188 ;               order = 3;
189 ;       else
190 ;               order = 4;
191         movd    edi, mm2                        ; edi = total_error_4
192         movq    mm4, mm1                        ; mm4 = total_error_3:total_error_2
193         psrlq   mm4, 32                         ; mm4 = 0:total_error_3
194         movd    edx, mm1                        ; edx = total_error_2
195         movd    esi, mm4                        ; esi = total_error_3
196         movq    mm3, mm0                        ; mm3 = total_error_1:total_error_0
197         psrlq   mm3, 32                         ; mm3 = 0:total_error_1
198         movd    ebx, mm0                        ; ebx = total_error_0
199         movd    ecx, mm3                        ; ecx = total_error_1
200         emms
201         mov     eax, ebx                        ; eax = total_error_0
202         cmp     ecx, ebx
203         cmovb   eax, ecx                        ; eax = min(total_error_0, total_error_1)
204         cmp     edx, eax
205         cmovb   eax, edx                        ; eax = min(total_error_0, total_error_1, total_error_2)
206         cmp     esi, eax
207         cmovb   eax, esi                        ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3)
208         cmp     edi, eax
209         cmovb   eax, edi                        ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3, total_error_4)
210
211         cmp     eax, ebx
212         jne     .not_order_0
213         xor     ebp, ebp
214         jmp     short .got_order
215 .not_order_0:
216         cmp     eax, ecx
217         jne     .not_order_1
218         mov     ebp, 1
219         jmp     short .got_order
220 .not_order_1:
221         cmp     eax, edx
222         jne     .not_order_2
223         mov     ebp, 2
224         jmp     short .got_order
225 .not_order_2:
226         cmp     eax, esi
227         jne     .not_order_3
228         mov     ebp, 3
229         jmp     short .got_order
230 .not_order_3:
231         mov     ebp, 4
232 .got_order:
233         ;       residual_bits_per_sample[0] = (FLAC__real)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
234         ;       residual_bits_per_sample[1] = (FLAC__real)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
235         ;       residual_bits_per_sample[2] = (FLAC__real)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
236         ;       residual_bits_per_sample[3] = (FLAC__real)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
237         ;       residual_bits_per_sample[4] = (FLAC__real)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
238         xor     eax, eax
239         cmp     eax, [esp + 40]
240         je      near .data_len_is_0
241         fild    dword [esp + 40]                ; ST = data_len (NOTE: assumes data_len is <2gigs)
242 .rbps_0:
243         test    ebx, ebx
244         jz      .total_error_0_is_0
245         fld1                                    ; ST = 1.0 data_len
246         mov     [esp], ebx
247         mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_0
248         mov     ebx, [esp + 44]
249         fild    qword [esp]                     ; ST = total_error_0 1.0 data_len
250         fdiv    st2                             ; ST = total_error_0/data_len 1.0 data_len
251         fldln2                                  ; ST = ln2 total_error_0/data_len 1.0 data_len
252         fmulp   st1                             ; ST = ln2*total_error_0/data_len 1.0 data_len
253         fyl2x                                   ; ST = log2(ln2*total_error_0/data_len) data_len
254         fstp    dword [ebx]                     ; residual_bits_per_sample[0] = log2(ln2*total_error_0/data_len)   ST = data_len
255         jmp     short .rbps_1
256 .total_error_0_is_0:
257         mov     ebx, [esp + 44]
258         mov     [ebx], eax                      ; residual_bits_per_sample[0] = 0.0
259 .rbps_1:
260         test    ecx, ecx
261         jz      .total_error_1_is_0
262         fld1                                    ; ST = 1.0 data_len
263         mov     [esp], ecx
264         mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_1
265         fild    qword [esp]                     ; ST = total_error_1 1.0 data_len
266         fdiv    st2                             ; ST = total_error_1/data_len 1.0 data_len
267         fldln2                                  ; ST = ln2 total_error_1/data_len 1.0 data_len
268         fmulp   st1                             ; ST = ln2*total_error_1/data_len 1.0 data_len
269         fyl2x                                   ; ST = log2(ln2*total_error_1/data_len) data_len
270         fstp    dword [ebx + 4]                 ; residual_bits_per_sample[1] = log2(ln2*total_error_1/data_len)   ST = data_len
271         jmp     short .rbps_2
272 .total_error_1_is_0:
273         mov     [ebx + 4], eax                  ; residual_bits_per_sample[1] = 0.0
274 .rbps_2:
275         test    edx, edx
276         jz      .total_error_2_is_0
277         fld1                                    ; ST = 1.0 data_len
278         mov     [esp], edx
279         mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_2
280         fild    qword [esp]                     ; ST = total_error_2 1.0 data_len
281         fdiv    st2                             ; ST = total_error_2/data_len 1.0 data_len
282         fldln2                                  ; ST = ln2 total_error_2/data_len 1.0 data_len
283         fmulp   st1                             ; ST = ln2*total_error_2/data_len 1.0 data_len
284         fyl2x                                   ; ST = log2(ln2*total_error_2/data_len) data_len
285         fstp    dword [ebx + 8]                 ; residual_bits_per_sample[2] = log2(ln2*total_error_2/data_len)   ST = data_len
286         jmp     short .rbps_3
287 .total_error_2_is_0:
288         mov     [ebx + 8], eax                  ; residual_bits_per_sample[2] = 0.0
289 .rbps_3:
290         test    esi, esi
291         jz      .total_error_3_is_0
292         fld1                                    ; ST = 1.0 data_len
293         mov     [esp], esi
294         mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_3
295         fild    qword [esp]                     ; ST = total_error_3 1.0 data_len
296         fdiv    st2                             ; ST = total_error_3/data_len 1.0 data_len
297         fldln2                                  ; ST = ln2 total_error_3/data_len 1.0 data_len
298         fmulp   st1                             ; ST = ln2*total_error_3/data_len 1.0 data_len
299         fyl2x                                   ; ST = log2(ln2*total_error_3/data_len) data_len
300         fstp    dword [ebx + 12]                ; residual_bits_per_sample[3] = log2(ln2*total_error_3/data_len)   ST = data_len
301         jmp     short .rbps_4
302 .total_error_3_is_0:
303         mov     [ebx + 12], eax                 ; residual_bits_per_sample[3] = 0.0
304 .rbps_4:
305         test    edi, edi
306         jz      .total_error_4_is_0
307         fld1                                    ; ST = 1.0 data_len
308         mov     [esp], edi
309         mov     [esp + 4], eax                  ; [esp] = (FLAC__uint64)total_error_4
310         fild    qword [esp]                     ; ST = total_error_4 1.0 data_len
311         fdiv    st2                             ; ST = total_error_4/data_len 1.0 data_len
312         fldln2                                  ; ST = ln2 total_error_4/data_len 1.0 data_len
313         fmulp   st1                             ; ST = ln2*total_error_4/data_len 1.0 data_len
314         fyl2x                                   ; ST = log2(ln2*total_error_4/data_len) data_len
315         fstp    dword [ebx + 16]                ; residual_bits_per_sample[4] = log2(ln2*total_error_4/data_len)   ST = data_len
316         jmp     short .rbps_end
317 .total_error_4_is_0:
318         mov     [ebx + 16], eax                 ; residual_bits_per_sample[4] = 0.0
319 .rbps_end:
320         fstp    st0                             ; ST = [empty]
321         jmp     short .end
322 .data_len_is_0:
323         ; data_len == 0, so residual_bits_per_sample[*] = 0.0
324         mov     ecx, 5                          ; eax still == 0, ecx = # of dwords of 0 to store
325         mov     edi, [esp + 44]
326         rep stosd
327
328 .end:
329         mov     eax, ebp                        ; return order
330         add     esp, byte 16
331         pop     edi
332         pop     esi
333         pop     ebx
334         pop     ebp
335         ret
336
337 end