summaryrefslogtreecommitdiffstats
path: root/libFLAC/ia32/bitreader_asm.nasm
diff options
context:
space:
mode:
Diffstat (limited to 'libFLAC/ia32/bitreader_asm.nasm')
-rw-r--r--libFLAC/ia32/bitreader_asm.nasm568
1 files changed, 568 insertions, 0 deletions
diff --git a/libFLAC/ia32/bitreader_asm.nasm b/libFLAC/ia32/bitreader_asm.nasm
new file mode 100644
index 0000000..5d1bbfa
--- /dev/null
+++ b/libFLAC/ia32/bitreader_asm.nasm
@@ -0,0 +1,568 @@
+; vim:filetype=nasm ts=8
+
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; - Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; - Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; - Neither the name of the Xiph.org Foundation nor the names of its
+; contributors may be used to endorse or promote products derived from
+; this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "nasm.h"
+
+ data_section
+
+cextern FLAC__crc16_table ; unsigned FLAC__crc16_table[256];
+cextern bitreader_read_from_client_ ; FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br);
+
+cglobal FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
+
+ code_section
+
+
+; **********************************************************************
+;
+; void FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+;
+; Some details like assertions and other checking is performed by the caller.
+ ALIGN 16
+cident FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
+
+ ;ASSERT(0 != br);
+ ;ASSERT(0 != br->buffer);
+ ; WATCHOUT: code only works if sizeof(brword)==32; we can make things much faster with this assertion
+ ;ASSERT(FLAC__BITS_PER_WORD == 32);
+ ;ASSERT(parameter < 32);
+ ; 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
+
+ ;; peppered throughout the code at major checkpoints are keys like this as to where things are at that point in time
+ ;; [esp + 16] unsigned parameter
+ ;; [esp + 12] unsigned nvals
+ ;; [esp + 8] int vals[]
+ ;; [esp + 4] FLAC__BitReader *br
+ mov eax, [esp + 12] ; if(nvals == 0)
+ test eax, eax
+ ja .nvals_gt_0
+ mov eax, 1 ; return true;
+ ret
+
+.nvals_gt_0:
+ push ebp
+ push ebx
+ push esi
+ push edi
+ sub esp, 4
+ ;; [esp + 36] unsigned parameter
+ ;; [esp + 32] unsigned nvals
+ ;; [esp + 28] int vals[]
+ ;; [esp + 24] FLAC__BitReader *br
+ ;; [esp] ucbits
+ mov ebp, [esp + 24] ; ebp <- br == br->buffer
+ mov esi, [ebp + 16] ; esi <- br->consumed_words (aka 'cwords' in the C version)
+ mov ecx, [ebp + 20] ; ecx <- br->consumed_bits (aka 'cbits' in the C version)
+ xor edi, edi ; edi <- 0 'uval'
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ ;; [ebp] br->buffer
+ ;; [ebp + 8] br->words
+ ;; [ebp + 12] br->bytes
+ ;; [ebp + 16] br->consumed_words
+ ;; [ebp + 20] br->consumed_bits
+ ;; [ebp + 24] br->read_crc
+ ;; [ebp + 28] br->crc16_align
+
+ ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+ mov eax, [ebp + 8] ; eax <- br->words
+ sub eax, esi ; eax <- br->words-cwords
+ shl eax, 2 ; eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+ add eax, [ebp + 12] ; eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+ shl eax, 3 ; eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+ sub eax, ecx ; eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+ mov [esp], eax ; ucbits <- eax
+
+ ALIGN 16
+.val_loop: ; while(1) {
+
+ ;
+ ; read unary part
+ ;
+.unary_loop: ; while(1) {
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ cmp esi, [ebp + 8] ; while(cwords < br->words) /* if we've not consumed up to a partial tail word... */
+ jae near .c1_next1
+.c1_loop: ; {
+ mov ebx, [ebp]
+ mov eax, [ebx + 4*esi] ; b = br->buffer[cwords]
+ mov edx, eax ; edx = br->buffer[cwords] (saved for later use)
+ shl eax, cl ; b = br->buffer[cwords] << cbits
+ test eax, eax ; (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
+ jz near .c1_next2 ; if(b) {
+ bsr ebx, eax
+ not ebx
+ and ebx, 31 ; ebx = 'i' = # of leading 0 bits in 'b' (eax)
+ add ecx, ebx ; cbits += i;
+ add edi, ebx ; uval += i;
+ add ecx, byte 1 ; cbits++; /* skip over stop bit */
+ test ecx, ~31
+ jz near .break1 ; if(cbits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(cbits == FLAC__BITS_PER_WORD) */
+ ; crc16_update_word_(br, br->buffer[cwords]);
+ push edi ; [need more registers]
+ bswap edx ; edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+ mov ecx, [ebp + 28] ; ecx <- br->crc16_align
+ mov eax, [ebp + 24] ; ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ mov edi, _FLAC__crc16_table
+%else
+ mov edi, FLAC__crc16_table
+%endif
+ ;; eax (ax) crc a.k.a. br->read_crc
+ ;; ebx (bl) intermediate result index into FLAC__crc16_table[]
+ ;; ecx br->crc16_align
+ ;; edx byteswapped brword to CRC
+ ;; esi cwords
+ ;; edi unsigned FLAC__crc16_table[]
+ ;; ebp br
+ test ecx, ecx ; switch(br->crc16_align) ...
+ jnz .c0b4 ; [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c0b0: xor dl, ah ; dl <- (crc>>8)^(word>>24)
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c0b1: xor dh, ah ; dh <- (crc>>8)^((word>>16)&0xff))
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shr edx, 16
+.c0b2: xor dl, ah ; dl <- (crc>>8)^((word>>8)&0xff))
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c0b3: xor dh, ah ; dh <- (crc>>8)^(word&0xff)
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ movzx eax, ax
+ mov [ebp + 24], eax ; br->read_crc <- crc
+ pop edi
+
+ add esi, byte 1 ; cwords++;
+ xor ecx, ecx ; cbits = 0;
+ ; }
+ jmp near .break1 ; goto break1;
+ ;; this section relocated out of the way for performance
+.c0b4:
+ mov [ebp + 28], dword 0 ; br->crc16_align <- 0
+ cmp ecx, 8
+ je .c0b1
+ shr edx, 16
+ cmp ecx, 16
+ je .c0b2
+ jmp .c0b3
+
+ ;; this section relocated out of the way for performance
+.c1b4:
+ mov [ebp + 28], dword 0 ; br->crc16_align <- 0
+ cmp ecx, 8
+ je .c1b1
+ shr edx, 16
+ cmp ecx, 16
+ je .c1b2
+ jmp .c1b3
+
+.c1_next2: ; } else {
+ ;; ecx cbits
+ ;; edx current brword 'b'
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ add edi, 32
+ sub edi, ecx ; uval += FLAC__BITS_PER_WORD - cbits;
+ ; crc16_update_word_(br, br->buffer[cwords]);
+ push edi ; [need more registers]
+ bswap edx ; edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+ mov ecx, [ebp + 28] ; ecx <- br->crc16_align
+ mov eax, [ebp + 24] ; ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ mov edi, _FLAC__crc16_table
+%else
+ mov edi, FLAC__crc16_table
+%endif
+ ;; eax (ax) crc a.k.a. br->read_crc
+ ;; ebx (bl) intermediate result index into FLAC__crc16_table[]
+ ;; ecx br->crc16_align
+ ;; edx byteswapped brword to CRC
+ ;; esi cwords
+ ;; edi unsigned FLAC__crc16_table[]
+ ;; ebp br
+ test ecx, ecx ; switch(br->crc16_align) ...
+ jnz .c1b4 ; [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c1b0: xor dl, ah ; dl <- (crc>>8)^(word>>24)
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c1b1: xor dh, ah ; dh <- (crc>>8)^((word>>16)&0xff))
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shr edx, 16
+.c1b2: xor dl, ah ; dl <- (crc>>8)^((word>>8)&0xff))
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c1b3: xor dh, ah ; dh <- (crc>>8)^(word&0xff)
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ movzx eax, ax
+ mov [ebp + 24], eax ; br->read_crc <- crc
+ pop edi
+
+ add esi, byte 1 ; cwords++;
+ xor ecx, ecx ; cbits = 0;
+ ; /* didn't find stop bit yet, have to keep going... */
+ ; }
+
+ cmp esi, [ebp + 8] ; } while(cwords < br->words) /* if we've not consumed up to a partial tail word... */
+ jb near .c1_loop
+
+.c1_next1:
+ ; at this point we've eaten up all the whole words; have to try
+ ; reading through any tail bytes before calling the read callback.
+ ; this is a repeat of the above logic adjusted for the fact we
+ ; don't have a whole word. note though if the client is feeding
+ ; us data a byte at a time (unlikely), br->consumed_bits may not
+ ; be zero.
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ mov edx, [ebp + 12] ; edx <- br->bytes
+ test edx, edx
+ jz .read1 ; if(br->bytes) { [NOTE: this case is rare so it doesn't have to be all that fast ]
+ mov ebx, [ebp]
+ shl edx, 3 ; edx <- const unsigned end = br->bytes * 8;
+ mov eax, [ebx + 4*esi] ; b = br->buffer[cwords]
+ xchg edx, ecx ; [edx <- cbits , ecx <- end]
+ mov ebx, 0xffffffff ; ebx <- FLAC__WORD_ALL_ONES
+ shr ebx, cl ; ebx <- FLAC__WORD_ALL_ONES >> end
+ not ebx ; ebx <- ~(FLAC__WORD_ALL_ONES >> end)
+ xchg edx, ecx ; [edx <- end , ecx <- cbits]
+ and eax, ebx ; b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end));
+ shl eax, cl ; b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end)) << cbits;
+ test eax, eax ; (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
+ jz .c1_next3 ; if(b) {
+ bsr ebx, eax
+ not ebx
+ and ebx, 31 ; ebx = 'i' = # of leading 0 bits in 'b' (eax)
+ add ecx, ebx ; cbits += i;
+ add edi, ebx ; uval += i;
+ add ecx, byte 1 ; cbits++; /* skip over stop bit */
+ jmp short .break1 ; goto break1;
+.c1_next3: ; } else {
+ sub edi, ecx
+ add edi, edx ; uval += end - cbits;
+ add ecx, edx ; cbits += end
+ ; /* didn't find stop bit yet, have to keep going... */
+ ; }
+ ; }
+.read1:
+ ; flush registers and read; bitreader_read_from_client_() does
+ ; not touch br->consumed_bits at all but we still need to set
+ ; it in case it fails and we have to return false.
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ mov [ebp + 16], esi ; br->consumed_words = cwords;
+ mov [ebp + 20], ecx ; br->consumed_bits = cbits;
+ push ecx ; /* save */
+ push ebp ; /* push br argument */
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ call _bitreader_read_from_client_
+%else
+ call bitreader_read_from_client_
+%endif
+ pop edx ; /* discard, unused */
+ pop ecx ; /* restore */
+ mov esi, [ebp + 16] ; cwords = br->consumed_words;
+ ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+ mov ebx, [ebp + 8] ; ebx <- br->words
+ sub ebx, esi ; ebx <- br->words-cwords
+ shl ebx, 2 ; ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+ add ebx, [ebp + 12] ; ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+ shl ebx, 3 ; ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+ sub ebx, ecx ; ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+ add ebx, edi ; ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits + uval
+ ; + uval to offset our count by the # of unary bits already
+ ; consumed before the read, because we will add these back
+ ; in all at once at break1
+ mov [esp], ebx ; ucbits <- ebx
+ test eax, eax ; if(!bitreader_read_from_client_(br))
+ jnz near .unary_loop
+ jmp .end ; return false; /* eax (the return value) is already 0 */
+ ; } /* end while(1) unary part */
+
+ ALIGN 16
+.break1:
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ ;; [esp] ucbits
+ sub [esp], edi ; ucbits -= uval;
+ sub dword [esp], byte 1 ; ucbits--; /* account for stop bit */
+
+ ;
+ ; read binary part
+ ;
+ mov ebx, [esp + 36] ; ebx <- parameter
+ test ebx, ebx ; if(parameter) {
+ jz near .break2
+.read2:
+ cmp [esp], ebx ; while(ucbits < parameter) {
+ jae .c2_next1
+ ; flush registers and read; bitreader_read_from_client_() does
+ ; not touch br->consumed_bits at all but we still need to set
+ ; it in case it fails and we have to return false.
+ mov [ebp + 16], esi ; br->consumed_words = cwords;
+ mov [ebp + 20], ecx ; br->consumed_bits = cbits;
+ push ecx ; /* save */
+ push ebp ; /* push br argument */
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ call _bitreader_read_from_client_
+%else
+ call bitreader_read_from_client_
+%endif
+ pop edx ; /* discard, unused */
+ pop ecx ; /* restore */
+ mov esi, [ebp + 16] ; cwords = br->consumed_words;
+ ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+ mov edx, [ebp + 8] ; edx <- br->words
+ sub edx, esi ; edx <- br->words-cwords
+ shl edx, 2 ; edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+ add edx, [ebp + 12] ; edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+ shl edx, 3 ; edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+ sub edx, ecx ; edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+ mov [esp], edx ; ucbits <- edx
+ test eax, eax ; if(!bitreader_read_from_client_(br))
+ jnz .read2
+ jmp .end ; return false; /* eax (the return value) is already 0 */
+ ; }
+.c2_next1:
+ ;; ebx parameter
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ ;; [esp] ucbits
+ cmp esi, [ebp + 8] ; if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+ jae near .c2_next2
+ test ecx, ecx ; if(cbits) {
+ jz near .c2_next3 ; /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ mov eax, 32
+ mov edx, [ebp]
+ sub eax, ecx ; const unsigned n = FLAC__BITS_PER_WORD - cbits;
+ mov edx, [edx + 4*esi] ; const brword word = br->buffer[cwords];
+ cmp ebx, eax ; if(parameter < n) {
+ jae .c2_next4
+ ; uval <<= parameter;
+ ; uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-parameter);
+ shl edx, cl
+ xchg ebx, ecx
+ shld edi, edx, cl
+ add ebx, ecx ; cbits += parameter;
+ xchg ebx, ecx ; ebx <- parameter, ecx <- cbits
+ jmp .break2 ; goto break2;
+ ; }
+.c2_next4:
+ ; uval <<= n;
+ ; uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
+%if 1
+ rol edx, cl ; @@@@@@OPT: may be faster to use rol to save edx so we can restore it for CRC'ing
+ ; @@@@@@OPT: or put parameter in ch instead and free up ebx completely again
+%else
+ shl edx, cl
+%endif
+ xchg eax, ecx
+ shld edi, edx, cl
+ xchg eax, ecx
+%if 1
+ ror edx, cl ; restored.
+%else
+ mov edx, [ebp]
+ mov edx, [edx + 4*esi]
+%endif
+ ; crc16_update_word_(br, br->buffer[cwords]);
+ push edi ; [need more registers]
+ push ebx ; [need more registers]
+ push eax ; [need more registers]
+ bswap edx ; edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+ mov ecx, [ebp + 28] ; ecx <- br->crc16_align
+ mov eax, [ebp + 24] ; ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ mov edi, _FLAC__crc16_table
+%else
+ mov edi, FLAC__crc16_table
+%endif
+ ;; eax (ax) crc a.k.a. br->read_crc
+ ;; ebx (bl) intermediate result index into FLAC__crc16_table[]
+ ;; ecx br->crc16_align
+ ;; edx byteswapped brword to CRC
+ ;; esi cwords
+ ;; edi unsigned FLAC__crc16_table[]
+ ;; ebp br
+ test ecx, ecx ; switch(br->crc16_align) ...
+ jnz .c2b4 ; [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c2b0: xor dl, ah ; dl <- (crc>>8)^(word>>24)
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c2b1: xor dh, ah ; dh <- (crc>>8)^((word>>16)&0xff))
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shr edx, 16
+.c2b2: xor dl, ah ; dl <- (crc>>8)^((word>>8)&0xff))
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c2b3: xor dh, ah ; dh <- (crc>>8)^(word&0xff)
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ movzx eax, ax
+ mov [ebp + 24], eax ; br->read_crc <- crc
+ pop eax
+ pop ebx
+ pop edi
+ add esi, byte 1 ; cwords++;
+ mov ecx, ebx
+ sub ecx, eax ; cbits = parameter - n;
+ 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 */
+ ; uval <<= cbits;
+ ; uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+ mov eax, [ebp]
+ mov eax, [eax + 4*esi]
+ shld edi, eax, cl
+ ; }
+ jmp .break2 ; goto break2;
+
+ ;; this section relocated out of the way for performance
+.c2b4:
+ mov [ebp + 28], dword 0 ; br->crc16_align <- 0
+ cmp ecx, 8
+ je .c2b1
+ shr edx, 16
+ cmp ecx, 16
+ je .c2b2
+ jmp .c2b3
+
+.c2_next3: ; } else {
+ mov ecx, ebx ; cbits = parameter;
+ ; uval <<= cbits;
+ ; uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+ mov eax, [ebp]
+ mov eax, [eax + 4*esi]
+ shld edi, eax, cl
+ jmp .break2 ; goto break2;
+ ; }
+.c2_next2: ; } else {
+ ; in this case we're starting our read at a partial tail word;
+ ; the reader has guaranteed that we have at least 'parameter'
+ ; bits available to read, which makes this case simpler.
+ ; uval <<= parameter;
+ ; if(cbits) {
+ ; /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ ; uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-parameter);
+ ; cbits += parameter;
+ ; goto break2;
+ ; } else {
+ ; cbits = parameter;
+ ; uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
+ ; goto break2;
+ ; }
+ ; the above is much shorter in assembly:
+ mov eax, [ebp]
+ mov eax, [eax + 4*esi] ; eax <- br->buffer[cwords]
+ shl eax, cl ; eax <- br->buffer[cwords] << cbits
+ add ecx, ebx ; cbits += parameter
+ xchg ebx, ecx ; ebx <- cbits, ecx <- parameter
+ shld edi, eax, cl ; uval <<= parameter <<< 'parameter' bits of tail word
+ xchg ebx, ecx ; ebx <- parameter, ecx <- cbits
+ ; }
+ ; }
+.break2:
+ sub [esp], ebx ; ucbits -= parameter;
+
+ ;
+ ; compose the value
+ ;
+ mov ebx, [esp + 28] ; ebx <- vals
+ mov edx, edi ; edx <- uval
+ and edi, 1 ; edi <- uval & 1
+ shr edx, 1 ; edx <- uval >> 1
+ neg edi ; edi <- -(int)(uval & 1)
+ xor edx, edi ; edx <- (uval >> 1 ^ -(int)(uval & 1))
+ mov [ebx], edx ; *vals <- edx
+ sub dword [esp + 32], byte 1 ; --nvals;
+ jz .finished ; if(nvals == 0) /* jump to finish */
+ xor edi, edi ; uval = 0;
+ add dword [esp + 28], 4 ; ++vals
+ jmp .val_loop ; }
+
+.finished:
+ mov [ebp + 16], esi ; br->consumed_words = cwords;
+ mov [ebp + 20], ecx ; br->consumed_bits = cbits;
+ mov eax, 1
+.end:
+ add esp, 4
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+ section .note.GNU-stack noalloc
+%endif