[Zlib-devel] infnew-5 available for testing

Chris Anderson christop at fellspt.charm.net
Wed Jan 15 23:56:01 EST 2003



I hacked up the gcc asm output of infnew-5/inffast.c pretty good, to see
what I could get out of it.

zbuflen   1024, clock 10.500, time 10.553
zbuflen   1024, clock 10.500, time 10.577
zbuflen   2048, clock 9.930, time 9.943
zbuflen   2048, clock 9.910, time 9.928
zbuflen   4096, clock 9.610, time 9.626
zbuflen   4096, clock 9.610, time 9.615
zbuflen   8192, clock 9.390, time 9.404
zbuflen   8192, clock 9.380, time 9.401
zbuflen  16384, clock 9.180, time 9.214
zbuflen  16384, clock 9.150, time 9.190
zbuflen  32768, clock 9.370, time 9.410
zbuflen  32768, clock 9.330, time 9.370
zbuflen  65536, clock 10.370, time 10.426
zbuflen  65536, clock 10.420, time 10.465

The critical paths in this code are only about 20 to 30 instructions long,
so a small change can have a pretty large effect.  At this speed, my
compiler is only about 10% off the mark, so I doubt the wisdom of this
hack.  Anyway, I attached a copy in case someone finds it useful or can
point out some wonderful x86 instruction I should have used.
-------------- next part --------------
/* infasm.S is based on:
 *
 * inffast.c -- fast decoding
 * Copyright (C) 1995-2003 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h 
 */

.print "WARNING: infasm.S is test code, it's stability is questionable"

.file "infasm.S"

.globl inflate_fast

/* for profile counters */

#define P(name) /* .globl p_ ## name */

P(break_loop)
P(test_for_end_of_block)
P(test_for_second_level_length)
P(test_for_second_level_dist)
P(do_copy2)
P(do_copy1)
P(contiguous_in_window)
P(wrap_around_window)
P(check_window)
P(get_op_bits2)
P(dodist)
P(get_bits2)
P(decode_distance)
P(get_op_bits1)
P(test_for_length_base)
P(output_char)
P(get_bits1)
P(do_loop)
P(inflate_fast)

.text
.align 4,0
.L_mask: /* mask[N] = ( 1 << N ) - 1 */
.long 0
.long 1
.long 3
.long 7
.long 15
.long 31
.long 63
.long 127
.long 255
.long 511
.long 1023
.long 2047
.long 4095
.long 8191
.long 16383
.long 32767
.long 65535
.long 131071
.long 262143
.long 524287
.long 1048575
.long 2097151
.long 4194303
.long 8388607
.long 16777215
.long 33554431
.long 67108863
.long 134217727
.long 268435455
.long 536870911
.long 1073741823
.long 2147483647
.long 4294967295

.align 4,0
.L_invalid_literal_length_code_msg:
.string "invalid literal/length code"

.align 4,0
.L_invalid_distance_code_msg:
.string "invalid distance code"

.align 4,0
.L_invalid_distance_too_far_msg:
.string "invalid distance too far back"

.data
.align 4,0
#undef P
#define P(name) /* p_ ## name: .long 0 */

P(break_loop)
P(test_for_end_of_block)
P(test_for_second_level_length)
P(test_for_second_level_dist)
P(do_copy2)
P(do_copy1)
P(contiguous_in_window)
P(wrap_around_window)
P(check_window)
P(get_op_bits2)
P(dodist)
P(get_bits2)
P(decode_distance)
P(get_op_bits1)
P(test_for_length_base)
P(output_char)
P(get_bits1)
P(do_loop)
P(inflate_fast)

#undef P
#define P(name) /*incl p_ ## name */
.text

#define local_var_size 52 /* how much local space for vars */
#define strm_sp        72 /* first arg: z_stream * (local_var_size + 20) */
#define start_sp       76 /* second arg: unsigned int (local_var_size + 24) */

/*
 * struct z_stream offsets, in zlib.h
 */
#define next_in_strm   0   /* strm->next_in */
#define avail_in_strm  4   /* strm->avail_in */
#define next_out_strm  12  /* strm->next_out */
#define avail_out_strm 16  /* strm->avail_out */
#define msg_strm       24  /* strm->msg */
#define state_strm     28  /* strm->state */

/*
 * struct inflate_state offsets, in inflate.h
 */
#define mode_state     0   /* state->mode */
#define wsize_state    32  /* state->wsize */
#define write_state    36  /* state->write */
#define window_state   40  /* state->window */
#define hold_state     44  /* state->hold */
#define bits_state     48  /* state->bits */
#define lencode_state  64  /* state->lencode */
#define distcode_state 68  /* state->distcode */
#define lenbits_state  72  /* state->lenbits */
#define distbits_state 76  /* state->distbits */

#define last           48  /* unsigned char* */
#define end            44  /* unsigned char* */
#define beg            40  /* unsigned char* */
#define out            36  /* unsigned char* */
#define in             32  /* unsigned char* */
#define window         28  /* unsigned char* */
#define lcode          24  /* code* */
#define dcode          20  /* code* */
#define wsize          16  /* unsigned int */
#define write          12  /* unsigned int */
#define lmask           8  /* unsigned int */
#define dmask           4  /* unsigned int */
#define len             0  /* unsigned int */

/*
 * typedef enum inflate_mode consts, in inflate.h
 */
#ifndef NO_GUNZIP
#define GUNZIP
#endif

#ifdef GUNZIP
#define INFLATE_MODE_TYPE 11  /* state->mode flags enum-ed in inflate.h */
#define INFLATE_MODE_BAD  26
#else
#define INFLATE_MODE_TYPE 3
#define INFLATE_MODE_BAD  17
#endif

.align 4,0x90
inflate_fast:
        pushl   %edi
        pushl   %esi
        pushl   %ebp
        pushl   %ebx
        subl    $local_var_size, %esp
        cld     /* save eflags? */

#define strm_r  %esi
#define state_r %edi

        movl    strm_sp(%esp), strm_r
        movl    state_strm(strm_r), state_r

        /* in = strm->next_in;
         * out = strm->next_out;
         * last = in + strm->avail_in - 5;
         * beg = out - (start - strm->avail_out);
         * end = out + (strm->avail_out - 257);
         */
        movl    next_in_strm(strm_r), %eax
        movl    next_out_strm(strm_r), %ebx
        movl    avail_in_strm(strm_r), %edx
        movl    avail_out_strm(strm_r), %ecx
        movl    start_sp(%esp), %ebp

        addl    %eax, %edx      /* avail_in += next_in */
        subl    $5, %edx        /* avail_in -= 5 */

        subl    %ecx, %ebp      /* start -= avail_out */
        negl    %ebp            /* start = -start */
        addl    %ebx, %ebp      /* start += next_out */

        subl    $257, %ecx      /* avail_out -= 257 */
        addl    %ebx, %ecx      /* avail_out += out */

        movl    %eax, in(%esp)
        movl    %ebx, out(%esp)
        movl    %edx, last(%esp)
        movl    %ebp, beg(%esp)
        movl    %ecx, end(%esp)

        /* wsize = state->wsize;
         * write = state->write;
         * window = state->window;
         * hold = state->hold;
         * bits = state->bits;
         * lcode = state->lencode;
         * dcode = state->distcode;
         * lmask = ( 1 << state->lenbits ) - 1;
         * dmask = ( 1 << state->distbits ) - 1;
         */

#define hold_r     %ebp
#define bits_r     %bl
#define bitslong_r %ebx

        movl    wsize_state(state_r), %eax
        movl    write_state(state_r), %ecx
        movl    window_state(state_r), %edx
        movl    hold_state(state_r), hold_r
        movl    bits_state(state_r), bitslong_r

        movl    %eax, wsize(%esp)
        movl    %ecx, write(%esp)
        movl    %edx, window(%esp)

        movl    lencode_state(state_r), %eax
        movl    distcode_state(state_r), %ecx

        movl    %eax, lcode(%esp)
        movl    %ecx, dcode(%esp)

        movl    lenbits_state(state_r), %ecx
        movl    distbits_state(state_r), %edx

        movl    .L_mask(,%ecx,4), %ecx
        movl    .L_mask(,%edx,4), %edx

        movl    %ecx, lmask(%esp)
        movl    %edx, dmask(%esp)

#undef strm_r
#undef state_r
#define in_r       %esi
#define out_r      %edi

        movl    in(%esp), in_r
        movl    out(%esp), out_r

        P(inflate_fast)

.align 16,0x90
.L_do_loop:
        P(do_loop)
        /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
         *
         * do { 
         *   if (bits < 15) {
         *     hold |= *((unsigned short *)in)++ << bits;
         *     bits += 16
         *   }
         *   this = lcode[hold & lmask]
         */
#if 0
        cmpb    $15, bits_r
        jae     .L_get_length_code      /* if (15 <= bits) */
#endif
        testb   $48, bits_r
        jnz     .L_get_length_code      /* if ((bits & 0x30) != 0) 38% */

        P(get_bits1)
        xorl    %eax, %eax
        movb    bits_r, %cl             /* %cl needs it for shifting */
        lodsw
        addb    $16, bits_r             /* bits += 16 */
        shll    %cl, %eax
        orl     %eax, hold_r            /* hold |= *((ushort *)in)++ << bits */

.L_get_length_code:
        movl    lmask(%esp), %eax       /* eax = lmask */
        movl    lcode(%esp), %ecx       /* ecx = lcode */
        andl    hold_r, %eax            /* eax &= hold */
        movl    (%ecx,%eax,4), %eax     /* eax = lcode[hold & lmask] */

.L_dolen:
        /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
         *
         * dolen:
         *    bits -= this.bits;
         *    hold >>= this.bits
         */
        movb    %ah, %cl                /* cl = this.bits */
        subb    %ah, bits_r             /* bits -= this.bits */
        shrl    %cl, hold_r             /* hold >>= this.bits */

        /* check if op is a literal
         * if (op == 0) {
         *    PUP(out) = this.val;
         *  }
         */
        testb   %al, %al
        jnz     .L_test_for_length_base /* if (op != 0) 45.7% */

        P(output_char)
        shrl    $16, %eax
        stosb

.L_while_test:
        /* while (in < last && out < end)
         */
        cmpl    out_r, end(%esp)
        jbe     .L_break_loop           /* if (out >= end) */

        cmpl    in_r, last(%esp)
        ja      .L_do_loop              /* if (in < last) */
        jmp     .L_break_loop

.L_test_for_length_base:
        P(test_for_length_base)
#define len_r %edx
        /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len
         *
         * else if (op & 16) {
         *   len = this.val
         *   op &= 15
         *   if (op) {
         *     if (op > bits) {
         *       hold |= *((unsigned short *)in)++ << bits;
         *       bits += 16
         *     }
         *     len += hold & mask[op];
         *     bits -= op;
         *     hold >>= op;
         *   }
         */

        movl    %eax, len_r             /* len = this */
        shrl    $16, len_r              /* len = this.val */
        testb   $16, %al
        jz      .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */

        andb    $15, %al                /* op &= 15 */
        jz      .L_save_len             /* if (!op) */
        movb    %al, %ch

/*.L_check_len_bits:*/
        cmpb    %ch, bits_r
        jae     .L_add_bits_to_len      /* if (op <= bits) */

        P(get_op_bits1)
        xorl    %eax, %eax
        movb    bits_r, %cl             /* %cl needs it for shifting */
        lodsw
        addb    $16, bits_r             /* bits += 16 */
        shll    %cl, %eax
        orl     %eax, hold_r            /* hold |= *in++ << bits */
        /*jmp     .L_check_len_bits (if adding bits by $8 with lodsb) */

.L_add_bits_to_len:
        movzbl  %ch, %ecx
        movl    .L_mask(,%ecx,4), %eax  /* eax = mask[op] */
        subb    %cl, bits_r
        andl    hold_r, %eax            /* eax &= hold */
        shrl    %cl, hold_r
        addl    %eax, len_r             /* len += hold & mask[op] */

.L_save_len:
        movl    len_r, len(%esp)        /* save len */

.L_decode_distance:
        P(decode_distance)
#define dist_r %edx
#undef  len_r
        /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist
         *
         *   if (bits < 15) {
         *     hold |= *((unsigned short *)in)++ << bits;
         *     bits += 16
         *   }
         *   this = dcode[hold & dmask];
         * dodist:
         *   bits -= this.bits;
         *   hold >>= this.bits;
         *   op = this.op;
         */
#if 0
        cmpb    $15, bits_r
        jae     .L_get_distance_code    /* if (15 <= bits) */
#endif
        testb   $48, bits_r
        jnz     .L_get_distance_code    /* if ((bits & 0x30) != 0) 69% */

        P(get_bits2)
        xorl    %eax, %eax
        movb    bits_r, %cl             /* %cl needs it for shifting */
        lodsw
        addb    $16, bits_r             /* bits += 16 */
        shll    %cl, %eax
        orl     %eax, hold_r            /* hold |= *((ushort *)in)++ << bits */

.L_get_distance_code:
        movl    dmask(%esp), %eax       /* eax = dmask */
        movl    dcode(%esp), %ecx       /* ecx = dcode */
        andl    hold_r, %eax            /* eax &= hold */
        movl    (%ecx,%eax,4), %eax     /* eax = dcode[hold & dmask] */

.L_dodist:
        P(dodist)
        movb    %ah, %cl
        subb    %ah, bits_r             /* bits -= this.bits */
        shrl    %cl, hold_r             /* hold >>= this.bits */

        /* if (op & 16) {
         *   dist = this.val
         *   op &= 15
         *   if (op > bits) {
         *     hold |= *((unsigned short *)in)++ << bits;
         *     bits += 16
         *   }
         *   dist += hold & mask[op];
         *   bits -= op;
         *   hold >>= op;
         */
        movl    %eax, dist_r            /* dist = this */
        shrl    $16, dist_r             /* dist = this.val */
        testb   $16, %al                /* if ((op & 16) == 0) */
        jz      .L_test_for_second_level_dist

        andb    $15, %al                /* op &= 15 */
        movb    %al, %ch

/*.L_check_dist_bits:*/
        cmpb    %ch, bits_r
        jae     .L_add_bits_to_dist     /* if (op <= bits) 97.6% */

        P(get_op_bits2)
        xorl    %eax, %eax
        movb    bits_r, %cl             /* %cl needs it for shifting */
        lodsw
        addb    $16, bits_r             /* bits += 16 */
        shll    %cl, %eax
        orl     %eax, hold_r            /* hold |= *in++ << bits */
        /*jmp     .L_check_dist_bits (if adding bits by $8 with lodsb) */

.L_add_bits_to_dist:
        movzbl  %ch, %ecx
        movl    .L_mask(,%ecx,4), %eax  /* eax = mask[op] */
        subb    %cl, bits_r
        andl    hold_r, %eax            /* eax &= hold */
        shrl    %cl, hold_r
        addl    %eax, dist_r            /* dist += hold & mask[op] */

.L_check_window:
        P(check_window)
        /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
         *       %ecx = nbytes
         *
         * nbytes = out - beg;
         * if (dist > nbytes) {
         *   if (dist > wsize) {
         *     invalid distance
         *   }
         *   from = window;
         *   nbytes = dist - nbytes;
         *   if (write == 0) {
         *     from += wsize - nbytes;
         */
#define nbytes_r %ecx

        movl    out_r, nbytes_r
        movl    in_r, in(%esp)          /* save in so from can use it's reg */
        subl    beg(%esp), nbytes_r     /* nbytes = out - beg */
        cmpl    dist_r, nbytes_r
        jae     .L_do_copy2             /* if (dist <= nbytes) 95.8% */

#define from_r %esi
#undef  in_r

        movl    wsize(%esp), %eax       /* prepare for dist compare */
        negl    nbytes_r                /* nbytes = -nbytes */
        movl    window(%esp), from_r    /* from = window */

        cmpl    dist_r, %eax
        jb      .L_invalid_distance_too_far /* if (dist < wsize) */

        addl    dist_r, nbytes_r        /* nbytes = dist - nbytes */
        cmpl    $0, write(%esp)
        jne     .L_wrap_around_window   /* if (write != 0) */

        subl    nbytes_r, %eax
        addl    %eax, from_r            /* from += wsize - nbytes */

#define len_r %eax
        /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
         *       %ecx = nbytes, %eax = len
         *
         *     if (nbytes < len) {
         *       len -= nbytes;
         *       do {
         *         PUP(out) = PUP(from);
         *       } while (--nbytes);
         *       from = out - dist;
         *     }
         *   }
         */

        movl    len(%esp), len_r
        cmpl    nbytes_r, len_r
        jbe     .L_do_copy1             /* if (nbytes >= len) */

        subl    nbytes_r, len_r         /* len -= nbytes */
        rep     movsb                   /* ecx = nbytes, esi = from, edi = out*/
        movl    out_r, from_r
        subl    dist_r, from_r          /* from = out - dist */
        jmp     .L_do_copy1

.L_wrap_around_window:
        P(wrap_around_window)
#define write_r %eax
        /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
         *       %ecx = nbytes, %eax = write, %eax = len
         *
         *   else if (write < nbytes) {
         *     from += wsize + write - nbytes;
         *     nbytes -= write;
         *     if (nbytes < len) {
         *       len -= nbytes;
         *       do {
         *         PUP(out) = PUP(from);
         *       } while (--nbytes);
         *       from = window;
         *       nbytes = write;
         *       if (nbytes < len) {
         *         len -= nbytes;
         *         do {
         *           PUP(out) = PUP(from);
         *         } while(--nbytes);
         *         from = out - dist;
         *       }
         *     }
         *   }
         */

        movl    write(%esp), write_r
        cmpl    write_r, nbytes_r
        jbe     .L_contiguous_in_window /* if (write >= nbytes) */

        addl    wsize(%esp), from_r
        addl    write_r, from_r
        subl    nbytes_r, from_r        /* from += wsize + write - nbytes */
        subl    write_r, nbytes_r       /* nbytes -= write */
#undef write_r

        movl    len(%esp), len_r
        cmpl    nbytes_r, len_r
        jbe     .L_do_copy1             /* if (nbytes >= len) */

        subl    nbytes_r, len_r         /* len -= nbytes */
        rep     movsb                   /* ecx = nbytes, esi = from, edi = out*/
        movl    window(%esp), from_r    /* from = window */
        movl    write(%esp), nbytes_r   /* nbytes = write */
        cmpl    nbytes_r, len_r
        jbe     .L_do_copy1             /* if (nbytes >= len) */

        subl    nbytes_r, len_r         /* len -= nbytes */
        rep     movsb                   /* ecx = nbytes, esi = from, edi = out*/
        movl    out_r, from_r
        subl    dist_r, from_r          /* from = out - dist */
        jmp     .L_do_copy1

.L_contiguous_in_window:
        P(contiguous_in_window)
#define write_r %eax
        /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
         *       %ecx = nbytes, %eax = write, %eax = len
         *
         *   else {
         *     from += write - nbytes;
         *     if (nbytes < len) {
         *       len -= nbytes;
         *       do {
         *         PUP(out) = PUP(from);
         *       } while (--nbytes);
         *       from = out - dist;
         *     }
         *   }
         */

        addl    write_r, from_r
        subl    nbytes_r, from_r        /* from += write - nbytes */
#undef write_r

        movl    len(%esp), len_r
        cmpl    nbytes_r, len_r
        jbe     .L_do_copy1             /* if (nbytes >= len) */

        subl    nbytes_r, len_r         /* len -= nbytes */
        rep     movsb                   /* ecx = nbytes, esi = from, edi = out*/
        movl    out_r, from_r
        subl    dist_r, from_r          /* from = out - dist */

.L_do_copy1:
        P(do_copy1)
#undef nbytes_r
#define in_r %esi
        /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out
         *       %eax = len
         *
         *     while (len > 0) {
         *       PUP(out) = PUP(from);
         *       len--;
         *     }
         *   }
         *   else {
         *     (.L_do_copy2)
         *   }
         * } while (in < last && out < end);
         */
        movl    len_r, %ecx             /* ecx = len for rep movsb */
        rep     movsb                   /* ecx = len, esi = from, edi = out */
        movl    in(%esp), in_r          /* move in back to %esi, toss from */
        jmp     .L_while_test

.L_do_copy2:
        P(do_copy2)
        /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out
         *       %edx = dist
         *   }
         *   else {
         *     from = out - dist;
         *     while (len > 0) {
         *       PUP(out) = PUP(from);
         *       len--;
         *     }
         *   }
         * } while (in < last && out < end);
         */
        movl    len(%esp), %ecx         /* ecx = len for rep movsb */
        movl    out_r, from_r
        subl    dist_r, from_r          /* from = out - dist */
        rep     movsb
        movl    in(%esp), in_r          /* move in back to %esi, toss from */
        jmp     .L_while_test

#undef len_r
#undef from_r
#undef dist_r

.L_test_for_second_level_dist:
        P(test_for_second_level_dist)
        /* else if ((op & 64) == 0) {
         *   this = dcode[this.val + (hold & mask[op])];
         * }
         */
        testb   $64, %al
        jnz     .L_invalid_distance_code  /* if ((op & 64) != 0) */

        movzbl  %al, %eax               /* eax = op */
        movl    dcode(%esp), %ecx       /* ecx = dcode */
        movl    .L_mask(,%eax,4), %eax  /* eax = mask[op] */
        andl    hold_r, %eax            /* eax &= hold */
        addl    %edx, %eax              /* eax += this.val */
        movl    (%ecx,%eax,4), %eax     /* eax = dcode[val + (hold&mask[op])] */
        jmp     .L_dodist

.L_invalid_distance_code:
        /* else {
         *   strm->msg = "invalid distance code";
         *   state->mode = BAD;
         * }
         */
        movl    $.L_invalid_distance_code_msg, %ecx
        movl    $INFLATE_MODE_BAD, %edx
        jmp     .L_update_stream_state

.L_test_for_second_level_length:
        P(test_for_second_level_length)
        /* else if ((op & 64) == 0) {
         *   this = lcode[this.val + (hold & mask[op])];
         * }
         */
        testb   $64, %al
        jnz     .L_test_for_end_of_block  /* if ((op & 64) != 0) */

        movzbl  %al, %eax               /* eax = op */
        movl    lcode(%esp), %ecx       /* ecx = lcode */
        movl    .L_mask(,%eax,4), %eax  /* eax = mask[op] */
        andl    hold_r, %eax            /* eax &= hold */
        addl    %edx, %eax              /* eax += this.val */
        movl    (%ecx,%eax,4), %eax     /* eax = lcode[val + (hold&mask[op])] */
        jmp     .L_dolen

.L_test_for_end_of_block:
        P(test_for_end_of_block)
        /* else if (op & 32) {
         *   state->mode = TYPE;
         *   break;
         * }
         */
        testb   $32, %al
        jz      .L_invalid_literal_length_code  /* if ((op & 32) == 0) */

        movl    $0, %ecx
        movl    $INFLATE_MODE_TYPE, %edx
        jmp     .L_update_stream_state

.L_invalid_literal_length_code:
        /* else {
         *   strm->msg = "invalid literal/length code";
         *   state->mode = BAD;
         * }
         */
        movl    $.L_invalid_literal_length_code_msg, %ecx
        movl    $INFLATE_MODE_BAD, %edx
        jmp     .L_update_stream_state

.L_invalid_distance_too_far:
        /* strm->msg = "invalid distance too far back";
         * state->mode = BAD;
         */
        movl    in(%esp), in_r          /* from_r has in's reg, put in back */
        movl    $.L_invalid_distance_too_far_msg, %ecx
        movl    $INFLATE_MODE_BAD, %edx
        jmp     .L_update_stream_state

.L_update_stream_state:
        /* set strm->msg = %ecx, strm->state->mode = %edx */
        movl    strm_sp(%esp), %eax
        testl   %ecx, %ecx              /* if (msg != NULL) */
        jz      .L_skip_msg
        movl    %ecx, msg_strm(%eax)    /* strm->msg = msg */
.L_skip_msg:
        movl    state_strm(%eax), %eax  /* state = strm->state */
        movl    %edx, mode_state(%eax)  /* state->mode = edx (BAD | TYPE) */

.L_break_loop:
        P(break_loop)

#define strm_r  %eax
#define state_r %edx

        /* len = bits >> 3;
         * in -= len;
         * bits -= len << 3;
         * hold &= (1U << bits) - 1;
         * state->hold = hold;
         * state->bits = bits;
         * strm->next_in = in;
         * strm->next_out = out;
         */
        movl    strm_sp(%esp), strm_r
        movl    bitslong_r, %ecx
        movl    state_strm(strm_r), state_r
        shrl    $3, %ecx
        subl    %ecx, in_r
        shll    $3, %ecx
        subb    %cl, bits_r
        movl    .L_mask(,bitslong_r,4), %ecx  /* ecx = mask[bits] */
        andl    %ecx, hold_r
        movl    bitslong_r, bits_state(state_r)
        movl    hold_r, hold_state(state_r)
        movl    out_r, next_out_strm(strm_r)
        movl    in_r, next_in_strm(strm_r)

#undef hold_r
#undef bits_r
#undef bitslong_r
#define last_r %ebx

        /* strm->avail_in = in < last ? 5 + (last - in) : 5 - (in - last) */
        movl    last(%esp), last_r
        cmpl    in_r, last_r
        jbe     .L_last_is_smaller     /* if (in >= last) */

        subl    in_r, last_r           /* last -= in */
        addl    $5, last_r             /* last += 5 */
        movl    last_r, avail_in_strm(strm_r)
        jmp     .L_fixup_out
.L_last_is_smaller:
        subl    last_r, in_r           /* in -= last */
        negl    in_r                   /* in = -in */
        addl    $5, in_r               /* in += 5 */
        movl    in_r, avail_in_strm(strm_r)

#undef last_r
#define end_r %ebx

.L_fixup_out:
        /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/
        movl    end(%esp), end_r
        cmpl    out_r, end_r
        jbe     .L_end_is_smaller      /* if (out >= end) */

        subl    out_r, end_r           /* end -= out */
        addl    $257, end_r            /* end += 257 */
        movl    end_r, avail_out_strm(strm_r)
        jmp     .L_done
.L_end_is_smaller:
        subl    end_r, out_r           /* out -= end */
        negl    out_r                  /* out = -out */
        addl    $257, out_r            /* out += 257 */
        movl    out_r, avail_out_strm(strm_r)

#undef end_r

.L_done:
        addl    $local_var_size, %esp
        popl    %ebx
        popl    %ebp
        popl    %esi
        popl    %edi
        ret

.type inflate_fast, at function
.size inflate_fast,.-inflate_fast


More information about the Zlib-devel mailing list