da630717e1f8ec2ab3a6350f5bb1052804dafbee
[flac.git] / src / libFLAC / ia32 / bitreader_asm.nasm
1 ;  vim:filetype=nasm ts=8
2
3 ;  libFLAC - Free Lossless Audio Codec library
4 ;  Copyright (C) 2001,2002,2003,2004,2005,2006,2007  Josh Coalson
5 ;
6 ;  Redistribution and use in source and binary forms, with or without
7 ;  modification, are permitted provided that the following conditions
8 ;  are met:
9 ;
10 ;  - Redistributions of source code must retain the above copyright
11 ;  notice, this list of conditions and the following disclaimer.
12 ;
13 ;  - Redistributions in binary form must reproduce the above copyright
14 ;  notice, this list of conditions and the following disclaimer in the
15 ;  documentation and/or other materials provided with the distribution.
16 ;
17 ;  - Neither the name of the Xiph.org Foundation nor the names of its
18 ;  contributors may be used to endorse or promote products derived from
19 ;  this software without specific prior written permission.
20 ;
21 ;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 ;  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 ;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 ;  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
25 ;  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 ;  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 ;  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 ;  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 ;  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 ;  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 ;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 %include "nasm.h"
34
35         data_section
36
37 extern FLAC__crc16_table                ; unsigned FLAC__crc16_table[256];
38 extern bitreader_read_from_client_      ; FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br);
39
40 cglobal FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
41
42         code_section
43
44
45 ; **********************************************************************
46 ;
47 ; void FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
48 ;
49 ; Some details like assertions and other checking is performed by the caller.
50         ALIGN 16
51 cident FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
52
53         ;ASSERT(0 != br);
54         ;ASSERT(0 != br->buffer);
55         ; WATCHOUT: code only works if sizeof(brword)==32; we can make things much faster with this assertion
56         ;ASSERT(FLAC__BITS_PER_WORD == 32);
57         ;ASSERT(parameter < 32);
58         ; the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it
59
60         ;; peppered throughout the code at major checkpoints are keys like this as to where things are at that point in time
61         ;; [esp + 16]   unsigned parameter
62         ;; [esp + 12]   unsigned nvals
63         ;; [esp + 8]    int vals[]
64         ;; [esp + 4]    FLAC__BitReader *br
65         mov     eax, [esp + 12]         ; if(nvals == 0)
66         test    eax, eax
67         ja      .nvals_gt_0
68         mov     eax, 1                  ;   return true;
69         ret
70
71 .nvals_gt_0:
72         push    ebp
73         push    ebx
74         push    esi
75         push    edi
76         sub     esp, 4
77         ;; [esp + 36]   unsigned parameter
78         ;; [esp + 32]   unsigned nvals
79         ;; [esp + 28]   int vals[]
80         ;; [esp + 24]   FLAC__BitReader *br
81         ;; [esp]        ucbits
82         mov     ebp, [esp + 24]         ; ebp <- br == br->buffer
83         mov     esi, [ebp + 16]         ; esi <- br->consumed_words (aka 'cwords' in the C version)
84         mov     ecx, [ebp + 20]         ; ecx <- br->consumed_bits  (aka 'cbits'  in the C version)
85         xor     edi, edi                ; edi <- 0  'uval'
86         ;; ecx          cbits
87         ;; esi          cwords
88         ;; edi          uval
89         ;; ebp          br
90         ;; [ebp]        br->buffer
91         ;; [ebp + 8]    br->words
92         ;; [ebp + 12]   br->bytes
93         ;; [ebp + 16]   br->consumed_words
94         ;; [ebp + 20]   br->consumed_bits
95         ;; [ebp + 24]   br->read_crc
96         ;; [ebp + 28]   br->crc16_align
97
98                                         ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
99         mov     eax, [ebp + 8]          ;   eax <- br->words
100         sub     eax, esi                ;   eax <- br->words-cwords
101         shl     eax, 2                  ;   eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD
102         add     eax, [ebp + 12]         ;   eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
103         shl     eax, 3                  ;   eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
104         sub     eax, ecx                ;   eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
105         mov     [esp], eax              ;   ucbits <- eax
106
107         ALIGN 16
108 .val_loop:                              ; while(1) {
109
110         ;
111         ; read unary part
112         ;
113 .unary_loop:                            ;   while(1) {
114         ;; ecx          cbits
115         ;; esi          cwords
116         ;; edi          uval
117         ;; ebp          br
118         cmp     esi, [ebp + 8]          ;     while(cwords < br->words)   /* if we've not consumed up to a partial tail word... */
119         jae     near .c1_next1
120 .c1_loop:                               ;     {
121         mov     ebx, [ebp]
122         mov     eax, [ebx + 4*esi]      ;       b = br->buffer[cwords]
123         mov     edx, eax                ;       edx = br->buffer[cwords] (saved for later use)
124         shl     eax, cl                 ;       b = br->buffer[cwords] << cbits
125         test    eax, eax                ;         (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
126         jz      near .c1_next2          ;       if(b) {
127         bsr     ebx, eax
128         not     ebx
129         and     ebx, 31                 ;         ebx = 'i' = # of leading 0 bits in 'b' (eax)
130         add     ecx, ebx                ;         cbits += i;
131         add     edi, ebx                ;         uval += i;
132         add     ecx, 1                  ;         cbits++; /* skip over stop bit */
133         test    ecx, ~31
134         jz      near .break1            ;         if(cbits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(cbits == FLAC__BITS_PER_WORD) */
135                                         ;           crc16_update_word_(br, br->buffer[cwords]);
136         push    edi                     ;               [need more registers]
137         bswap   edx                     ;               edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
138         mov     ecx, [ebp + 28]         ;               ecx <- br->crc16_align
139         mov     eax, [ebp + 24]         ;               ax <- br->read_crc (a.k.a. crc)
140         mov     edi, FLAC__crc16_table
141         ;; eax (ax)     crc a.k.a. br->read_crc
142         ;; ebx (bl)     intermediate result index into FLAC__crc16_table[]
143         ;; ecx          br->crc16_align
144         ;; edx          byteswapped brword to CRC
145         ;; esi          cwords
146         ;; edi          unsigned FLAC__crc16_table[]
147         ;; ebp          br
148         test    ecx, ecx                ;               switch(br->crc16_align) ...
149         jnz     .c0b4                   ;               [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
150 .c0b0:  xor     dl, ah                  ;               dl <- (crc>>8)^(word>>24)
151         movzx   ebx, dl
152         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
153         shl     eax, 8                  ;               ax <- (crc<<8)
154         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
155 .c0b1:  xor     dh, ah                  ;               dh <- (crc>>8)^((word>>16)&0xff))
156         movzx   ebx, dh
157         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
158         shl     eax, 8                  ;               ax <- (crc<<8)
159         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
160         shr     edx, 16
161 .c0b2:  xor     dl, ah                  ;               dl <- (crc>>8)^((word>>8)&0xff))
162         movzx   ebx, dl
163         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
164         shl     eax, 8                  ;               ax <- (crc<<8)
165         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
166 .c0b3:  xor     dh, ah                  ;               dh <- (crc>>8)^(word&0xff)
167         movzx   ebx, dh
168         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
169         shl     eax, 8                  ;               ax <- (crc<<8)
170         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
171         movzx   eax, ax
172         mov     [ebp + 24], eax         ;               br->read_crc <- crc
173         pop     edi
174
175         add     esi, 1                  ;           cwords++;
176         xor     ecx, ecx                ;           cbits = 0;
177                                         ;         }
178         jmp     near .break1            ;         goto break1;
179         ;; this section relocated out of the way for performance
180 .c0b4:
181         mov     [ebp + 28], dword 0     ;               br->crc16_align <- 0
182         cmp     ecx, 8
183         je      .c0b1
184         shr     edx, 16
185         cmp     ecx, 16
186         je      .c0b2
187         jmp     .c0b3
188
189         ;; this section relocated out of the way for performance
190 .c1b4:
191         mov     [ebp + 28], dword 0     ;               br->crc16_align <- 0
192         cmp     ecx, 8
193         je      .c1b1
194         shr     edx, 16
195         cmp     ecx, 16
196         je      .c1b2
197         jmp     .c1b3
198
199 .c1_next2:                              ;       } else {
200         ;; ecx          cbits
201         ;; edx          current brword 'b'
202         ;; esi          cwords
203         ;; edi          uval
204         ;; ebp          br
205         add     edi, 32
206         sub     edi, ecx                ;         uval += FLAC__BITS_PER_WORD - cbits;
207                                         ;         crc16_update_word_(br, br->buffer[cwords]);
208         push    edi                     ;               [need more registers]
209         bswap   edx                     ;               edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
210         mov     ecx, [ebp + 28]         ;               ecx <- br->crc16_align
211         mov     eax, [ebp + 24]         ;               ax <- br->read_crc (a.k.a. crc)
212         mov     edi, FLAC__crc16_table
213         ;; eax (ax)     crc a.k.a. br->read_crc
214         ;; ebx (bl)     intermediate result index into FLAC__crc16_table[]
215         ;; ecx          br->crc16_align
216         ;; edx          byteswapped brword to CRC
217         ;; esi          cwords
218         ;; edi          unsigned FLAC__crc16_table[]
219         ;; ebp          br
220         test    ecx, ecx                ;               switch(br->crc16_align) ...
221         jnz     .c1b4                   ;               [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
222 .c1b0:  xor     dl, ah                  ;               dl <- (crc>>8)^(word>>24)
223         movzx   ebx, dl
224         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
225         shl     eax, 8                  ;               ax <- (crc<<8)
226         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
227 .c1b1:  xor     dh, ah                  ;               dh <- (crc>>8)^((word>>16)&0xff))
228         movzx   ebx, dh
229         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
230         shl     eax, 8                  ;               ax <- (crc<<8)
231         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
232         shr     edx, 16
233 .c1b2:  xor     dl, ah                  ;               dl <- (crc>>8)^((word>>8)&0xff))
234         movzx   ebx, dl
235         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
236         shl     eax, 8                  ;               ax <- (crc<<8)
237         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
238 .c1b3:  xor     dh, ah                  ;               dh <- (crc>>8)^(word&0xff)
239         movzx   ebx, dh
240         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
241         shl     eax, 8                  ;               ax <- (crc<<8)
242         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
243         movzx   eax, ax
244         mov     [ebp + 24], eax         ;               br->read_crc <- crc
245         pop     edi
246
247         add     esi, 1                  ;         cwords++;
248         xor     ecx, ecx                ;         cbits = 0;
249                                         ;         /* didn't find stop bit yet, have to keep going... */
250                                         ;       }
251
252         cmp     esi, [ebp + 8]          ;     } while(cwords < br->words)   /* if we've not consumed up to a partial tail word... */
253         jb      near .c1_loop
254
255 .c1_next1:
256         ; at this point we've eaten up all the whole words; have to try
257         ; reading through any tail bytes before calling the read callback.
258         ; this is a repeat of the above logic adjusted for the fact we
259         ; don't have a whole word.  note though if the client is feeding
260         ; us data a byte at a time (unlikely), br->consumed_bits may not
261         ; be zero.
262         ;; ecx          cbits
263         ;; esi          cwords
264         ;; edi          uval
265         ;; ebp          br
266         mov     edx, [ebp + 12]         ;     edx <- br->bytes
267         test    edx, edx
268         jz      .read1                  ;     if(br->bytes) {  [NOTE: this case is rare so it doesn't have to be all that fast ]
269         mov     ebx, [ebp]
270         shl     edx, 3                  ;       edx <- const unsigned end = br->bytes * 8;
271         mov     eax, [ebx + 4*esi]      ;       b = br->buffer[cwords]
272         xchg    edx, ecx                ;       [edx <- cbits , ecx <- end]
273         mov     ebx, 0xffffffff         ;       ebx <- FLAC__WORD_ALL_ONES
274         shr     ebx, cl                 ;       ebx <- FLAC__WORD_ALL_ONES >> end
275         not     ebx                     ;       ebx <- ~(FLAC__WORD_ALL_ONES >> end)
276         xchg    edx, ecx                ;       [edx <- end , ecx <- cbits]
277         and     eax, ebx                ;       b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end));
278         shl     eax, cl                 ;       b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end)) << cbits;
279         test    eax, eax                ;         (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
280         jz      .c1_next3               ;       if(b) {
281         bsr     ebx, eax
282         not     ebx
283         and     ebx, 31                 ;         ebx = 'i' = # of leading 0 bits in 'b' (eax)
284         add     ecx, ebx                ;         cbits += i;
285         add     edi, ebx                ;         uval += i;
286         add     ecx, 1                  ;         cbits++; /* skip over stop bit */
287         jmp     short .break1           ;         goto break1;
288 .c1_next3:                              ;       } else {
289         sub     edi, ecx
290         add     edi, edx                ;         uval += end - cbits;
291         add     ecx, edx                ;         cbits += end
292                                         ;         /* didn't find stop bit yet, have to keep going... */
293                                         ;       }
294                                         ;     }
295 .read1:
296         ; flush registers and read; bitreader_read_from_client_() does
297         ; not touch br->consumed_bits at all but we still need to set
298         ; it in case it fails and we have to return false.
299         ;; ecx          cbits
300         ;; esi          cwords
301         ;; edi          uval
302         ;; ebp          br
303         mov     [ebp + 16], esi         ;     br->consumed_words = cwords;
304         mov     [ebp + 20], ecx         ;     br->consumed_bits = cbits;
305         push    ecx                     ;     /* save */
306         push    ebp                     ;     /* push br argument */
307         call    bitreader_read_from_client_
308         pop     edx                     ;     /* discard, unused */
309         pop     ecx                     ;     /* restore */
310         mov     esi, [ebp + 16]         ;     cwords = br->consumed_words;
311                                         ;     ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
312         mov     ebx, [ebp + 8]          ;       ebx <- br->words
313         sub     ebx, esi                ;       ebx <- br->words-cwords
314         shl     ebx, 2                  ;       ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
315         add     ebx, [ebp + 12]         ;       ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
316         shl     ebx, 3                  ;       ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
317         sub     ebx, ecx                ;       ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
318         add     ebx, edi                ;       ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits + uval
319                                         ;           + uval to offset our count by the # of unary bits already
320                                         ;           consumed before the read, because we will add these back
321                                         ;           in all at once at break1
322         mov     [esp], ebx              ;       ucbits <- ebx
323         test    eax, eax                ;     if(!bitreader_read_from_client_(br))
324         jnz     near .unary_loop
325         jmp     .end                    ;       return false; /* eax (the return value) is already 0 */
326                                         ;   } /* end while(1) unary part */
327
328         ALIGN 16
329 .break1:
330         ;; ecx          cbits
331         ;; esi          cwords
332         ;; edi          uval
333         ;; ebp          br
334         ;; [esp]        ucbits
335         sub     [esp], edi              ;   ucbits -= uval;
336         sub     dword [esp], 1          ;   ucbits--; /* account for stop bit */
337
338         ;
339         ; read binary part
340         ;
341         mov     ebx, [esp + 36]         ;   ebx <- parameter
342         test    ebx, ebx                ;   if(parameter) {
343         jz      near .break2
344 .read2:
345         cmp     [esp], ebx              ;     while(ucbits < parameter) {
346         jae     .c2_next1
347         ; flush registers and read; bitreader_read_from_client_() does
348         ; not touch br->consumed_bits at all but we still need to set
349         ; it in case it fails and we have to return false.
350         mov     [ebp + 16], esi         ;       br->consumed_words = cwords;
351         mov     [ebp + 20], ecx         ;       br->consumed_bits = cbits;
352         push    ecx                     ;       /* save */
353         push    ebp                     ;       /* push br argument */
354         call    bitreader_read_from_client_
355         pop     edx                     ;       /* discard, unused */
356         pop     ecx                     ;       /* restore */
357         mov     esi, [ebp + 16]         ;       cwords = br->consumed_words;
358                                         ;       ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
359         mov     edx, [ebp + 8]          ;         edx <- br->words
360         sub     edx, esi                ;         edx <- br->words-cwords
361         shl     edx, 2                  ;         edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
362         add     edx, [ebp + 12]         ;         edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
363         shl     edx, 3                  ;         edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
364         sub     edx, ecx                ;         edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
365         mov     [esp], edx              ;         ucbits <- edx
366         test    eax, eax                ;       if(!bitreader_read_from_client_(br))
367         jnz     .read2
368         jmp     .end                    ;         return false; /* eax (the return value) is already 0 */
369                                         ;     }
370 .c2_next1:
371         ;; ebx          parameter
372         ;; ecx          cbits
373         ;; esi          cwords
374         ;; edi          uval
375         ;; ebp          br
376         ;; [esp]        ucbits
377         cmp     esi, [ebp + 8]          ;     if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
378         jae     near .c2_next2
379         test    ecx, ecx                ;       if(cbits) {
380         jz      near .c2_next3          ;         /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
381         mov     eax, 32
382         mov     edx, [ebp]
383         sub     eax, ecx                ;         const unsigned n = FLAC__BITS_PER_WORD - cbits;
384         mov     edx, [edx + 4*esi]      ;         const brword word = br->buffer[cwords];
385         cmp     ebx, eax                ;         if(parameter < n) {
386         jae     .c2_next4
387                                         ;           uval <<= parameter;
388                                         ;           uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-parameter);
389         shl     edx, cl
390         xchg    ebx, ecx
391         shld    edi, edx, cl
392         add     ebx, ecx                ;           cbits += parameter;
393         xchg    ebx, ecx                ;           ebx <- parameter, ecx <- cbits
394         jmp     .break2                 ;           goto break2;
395                                         ;         }
396 .c2_next4:
397                                         ;         uval <<= n;
398                                         ;         uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
399 %if 1
400         rol     edx, cl                 ;            @@@@@@OPT: may be faster to use rol to save edx so we can restore it for CRC'ing
401                                         ;            @@@@@@OPT: or put parameter in ch instead and free up ebx completely again
402 %else
403         shl     edx, cl
404 %endif
405         xchg    eax, ecx
406         shld    edi, edx, cl
407         xchg    eax, ecx
408 %if 1
409         ror     edx, cl                 ;            restored.
410 %else
411         mov     edx, [ebp]
412         mov     edx, [edx + 4*esi]
413 %endif
414                                         ;         crc16_update_word_(br, br->buffer[cwords]);
415         push    edi                     ;               [need more registers]
416         push    ebx                     ;               [need more registers]
417         push    eax                     ;               [need more registers]
418         bswap   edx                     ;               edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
419         mov     ecx, [ebp + 28]         ;               ecx <- br->crc16_align
420         mov     eax, [ebp + 24]         ;               ax <- br->read_crc (a.k.a. crc)
421         mov     edi, FLAC__crc16_table
422         ;; eax (ax)     crc a.k.a. br->read_crc
423         ;; ebx (bl)     intermediate result index into FLAC__crc16_table[]
424         ;; ecx          br->crc16_align
425         ;; edx          byteswapped brword to CRC
426         ;; esi          cwords
427         ;; edi          unsigned FLAC__crc16_table[]
428         ;; ebp          br
429         test    ecx, ecx                ;               switch(br->crc16_align) ...
430         jnz     .c2b4                   ;               [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
431 .c2b0:  xor     dl, ah                  ;               dl <- (crc>>8)^(word>>24)
432         movzx   ebx, dl
433         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
434         shl     eax, 8                  ;               ax <- (crc<<8)
435         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
436 .c2b1:  xor     dh, ah                  ;               dh <- (crc>>8)^((word>>16)&0xff))
437         movzx   ebx, dh
438         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
439         shl     eax, 8                  ;               ax <- (crc<<8)
440         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
441         shr     edx, 16
442 .c2b2:  xor     dl, ah                  ;               dl <- (crc>>8)^((word>>8)&0xff))
443         movzx   ebx, dl
444         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
445         shl     eax, 8                  ;               ax <- (crc<<8)
446         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
447 .c2b3:  xor     dh, ah                  ;               dh <- (crc>>8)^(word&0xff)
448         movzx   ebx, dh
449         mov     ecx, [ebx*4 + edi]      ;               cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
450         shl     eax, 8                  ;               ax <- (crc<<8)
451         xor     eax, ecx                ;               crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
452         movzx   eax, ax
453         mov     [ebp + 24], eax         ;               br->read_crc <- crc
454         pop     eax
455         pop     ebx
456         pop     edi
457         add     esi, 1                  ;         cwords++;
458         mov     ecx, ebx
459         sub     ecx, eax                ;         cbits = parameter - n;
460         jz      .break2                 ;         if(cbits) { /* parameter > n, i.e. if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
461                                         ;           uval <<= cbits;
462                                         ;           uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
463         mov     eax, [ebp]
464         mov     eax, [eax + 4*esi]
465         shld    edi, eax, cl
466                                         ;         }
467         jmp     .break2                 ;         goto break2;
468
469         ;; this section relocated out of the way for performance
470 .c2b4:
471         mov     [ebp + 28], dword 0     ;               br->crc16_align <- 0
472         cmp     ecx, 8
473         je      .c2b1
474         shr     edx, 16
475         cmp     ecx, 16
476         je      .c2b2
477         jmp     .c2b3
478
479 .c2_next3:                              ;       } else {
480         mov     ecx, ebx                ;         cbits = parameter;
481                                         ;         uval <<= cbits;
482                                         ;         uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
483         mov     eax, [ebp]
484         mov     eax, [eax + 4*esi]
485         shld    edi, eax, cl
486         jmp     .break2                 ;         goto break2;
487                                         ;       }
488 .c2_next2:                              ;     } else {
489         ; in this case we're starting our read at a partial tail word;
490         ; the reader has guaranteed that we have at least 'parameter'
491         ; bits available to read, which makes this case simpler.
492                                         ;       uval <<= parameter;
493                                         ;       if(cbits) {
494                                         ;         /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
495                                         ;         uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-parameter);
496                                         ;         cbits += parameter;
497                                         ;         goto break2;
498                                         ;       } else {
499                                         ;         cbits = parameter;
500                                         ;         uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
501                                         ;         goto break2;
502                                         ;       }
503                                         ;       the above is much shorter in assembly:
504         mov     eax, [ebp]
505         mov     eax, [eax + 4*esi]      ;       eax <- br->buffer[cwords]
506         shl     eax, cl                 ;       eax <- br->buffer[cwords] << cbits
507         add     ecx, ebx                ;       cbits += parameter
508         xchg    ebx, ecx                ;       ebx <- cbits, ecx <- parameter
509         shld    edi, eax, cl            ;       uval <<= parameter <<< 'parameter' bits of tail word
510         xchg    ebx, ecx                ;       ebx <- parameter, ecx <- cbits
511                                         ;     }
512                                         ;   }
513 .break2:
514         sub     [esp], ebx              ;   ucbits -= parameter;
515
516         ;
517         ; compose the value
518         ;
519         mov     ebx, [esp + 28]         ;   ebx <- vals
520         mov     edx, edi                ;   edx <- uval
521         and     edi, 1                  ;   edi <- uval & 1
522         shr     edx, 1                  ;   edx <- uval >> 1
523         neg     edi                     ;   edi <- -(int)(uval & 1)
524         xor     edx, edi                ;   edx <- (uval >> 1 ^ -(int)(uval & 1))
525         mov     [ebx], edx              ;   *vals <- edx
526         sub     dword [esp + 32], 1     ;   --nvals;
527         jz      .finished               ;   if(nvals == 0) /* jump to finish */
528         xor     edi, edi                ;   uval = 0;
529         add     dword [esp + 28], 4     ;   ++vals
530         jmp     .val_loop               ; }
531
532 .finished:
533         mov     [ebp + 16], esi         ; br->consumed_words = cwords;
534         mov     [ebp + 20], ecx         ; br->consumed_bits = cbits;
535         mov     eax, 1
536 .end:
537         add     esp, 4
538         pop     edi
539         pop     esi
540         pop     ebx
541         pop     ebp
542         ret
543
544 end
545
546 %ifdef OBJ_FORMAT_elf
547         section .note.GNU-stack noalloc
548 %endif