new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / external / zlib-1.2.11 / contrib / inflate86 / inffast.S
1 /*
2  * inffast.S is a hand tuned assembler version of:
3  *
4  * inffast.c -- fast decoding
5  * Copyright (C) 1995-2003 Mark Adler
6  * For conditions of distribution and use, see copyright notice in zlib.h
7  *
8  * Copyright (C) 2003 Chris Anderson <christop@charm.net>
9  * Please use the copyright conditions above.
10  *
11  * This version (Jan-23-2003) of inflate_fast was coded and tested under
12  * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution.  On that
13  * machine, I found that gzip style archives decompressed about 20% faster than
14  * the gcc-3.2 -O3 -fomit-frame-pointer compiled version.  Your results will
15  * depend on how large of a buffer is used for z_stream.next_in & next_out
16  * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in
17  * stream processing I/O and crc32/addler32.  In my case, this routine used
18  * 70% of the cpu time and crc32 used 20%.
19  *
20  * I am confident that this version will work in the general case, but I have
21  * not tested a wide variety of datasets or a wide variety of platforms.
22  *
23  * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating.
24  * It should be a runtime flag instead of compile time flag...
25  *
26  * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction.
27  * With -DUSE_MMX, only MMX code is compiled.  With -DNO_MMX, only non-MMX code
28  * is compiled.  Without either option, runtime detection is enabled.  Runtime
29  * detection should work on all modern cpus and the recomended algorithm (flip
30  * ID bit on eflags and then use the cpuid instruction) is used in many
31  * multimedia applications.  Tested under win2k with gcc-2.95 and gas-2.12
32  * distributed with cygwin3.  Compiling with gcc-2.95 -c inffast.S -o
33  * inffast.obj generates a COFF object which can then be linked with MSVC++
34  * compiled code.  Tested under FreeBSD 4.7 with gcc-2.95.
35  *
36  * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and
37  * slower than compiler generated code).  Adjusted cpuid check to use the MMX
38  * code only for Pentiums < P4 until I have more data on the P4.  Speed
39  * improvment is only about 15% on the Athlon when compared with code generated
40  * with MSVC++.  Not sure yet, but I think the P4 will also be slower using the
41  * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and
42  * have less latency than MMX ops.  Added code to buffer the last 11 bytes of
43  * the input stream since the MMX code grabs bits in chunks of 32, which
44  * differs from the inffast.c algorithm.  I don't think there would have been
45  * read overruns where a page boundary was crossed (a segfault), but there
46  * could have been overruns when next_in ends on unaligned memory (unintialized
47  * memory read).
48  *
49  * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX.  I created a C
50  * version of the non-MMX code so that it doesn't depend on zstrm and zstate
51  * structure offsets which are hard coded in this file.  This was last tested
52  * with zlib-1.2.0 which is currently in beta testing, newer versions of this
53  * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and
54  * http://www.charm.net/~christop/zlib/
55  */
56
57
58 /*
59  * if you have underscore linking problems (_inflate_fast undefined), try
60  * using -DGAS_COFF
61  */
62 #if ! defined( GAS_COFF ) && ! defined( GAS_ELF )
63
64 #if defined( WIN32 ) || defined( __CYGWIN__ )
65 #define GAS_COFF /* windows object format */
66 #else
67 #define GAS_ELF
68 #endif
69
70 #endif /* ! GAS_COFF && ! GAS_ELF */
71
72
73 #if defined( GAS_COFF )
74
75 /* coff externals have underscores */
76 #define inflate_fast _inflate_fast
77 #define inflate_fast_use_mmx _inflate_fast_use_mmx
78
79 #endif /* GAS_COFF */
80
81
82 .file "inffast.S"
83
84 .globl inflate_fast
85
86 .text
87 .align 4,0
88 .L_invalid_literal_length_code_msg:
89 .string "invalid literal/length code"
90
91 .align 4,0
92 .L_invalid_distance_code_msg:
93 .string "invalid distance code"
94
95 .align 4,0
96 .L_invalid_distance_too_far_msg:
97 .string "invalid distance too far back"
98
99 #if ! defined( NO_MMX )
100 .align 4,0
101 .L_mask: /* mask[N] = ( 1 << N ) - 1 */
102 .long 0
103 .long 1
104 .long 3
105 .long 7
106 .long 15
107 .long 31
108 .long 63
109 .long 127
110 .long 255
111 .long 511
112 .long 1023
113 .long 2047
114 .long 4095
115 .long 8191
116 .long 16383
117 .long 32767
118 .long 65535
119 .long 131071
120 .long 262143
121 .long 524287
122 .long 1048575
123 .long 2097151
124 .long 4194303
125 .long 8388607
126 .long 16777215
127 .long 33554431
128 .long 67108863
129 .long 134217727
130 .long 268435455
131 .long 536870911
132 .long 1073741823
133 .long 2147483647
134 .long 4294967295
135 #endif /* NO_MMX */
136
137 .text
138
139 /*
140  * struct z_stream offsets, in zlib.h
141  */
142 #define next_in_strm   0   /* strm->next_in */
143 #define avail_in_strm  4   /* strm->avail_in */
144 #define next_out_strm  12  /* strm->next_out */
145 #define avail_out_strm 16  /* strm->avail_out */
146 #define msg_strm       24  /* strm->msg */
147 #define state_strm     28  /* strm->state */
148
149 /*
150  * struct inflate_state offsets, in inflate.h
151  */
152 #define mode_state     0   /* state->mode */
153 #define wsize_state    32  /* state->wsize */
154 #define write_state    40  /* state->write */
155 #define window_state   44  /* state->window */
156 #define hold_state     48  /* state->hold */
157 #define bits_state     52  /* state->bits */
158 #define lencode_state  68  /* state->lencode */
159 #define distcode_state 72  /* state->distcode */
160 #define lenbits_state  76  /* state->lenbits */
161 #define distbits_state 80  /* state->distbits */
162
163 /*
164  * inflate_fast's activation record
165  */
166 #define local_var_size 64 /* how much local space for vars */
167 #define strm_sp        88 /* first arg: z_stream * (local_var_size + 24) */
168 #define start_sp       92 /* second arg: unsigned int (local_var_size + 28) */
169
170 /*
171  * offsets for local vars on stack
172  */
173 #define out            60  /* unsigned char* */
174 #define window         56  /* unsigned char* */
175 #define wsize          52  /* unsigned int */
176 #define write          48  /* unsigned int */
177 #define in             44  /* unsigned char* */
178 #define beg            40  /* unsigned char* */
179 #define buf            28  /* char[ 12 ] */
180 #define len            24  /* unsigned int */
181 #define last           20  /* unsigned char* */
182 #define end            16  /* unsigned char* */
183 #define dcode          12  /* code* */
184 #define lcode           8  /* code* */
185 #define dmask           4  /* unsigned int */
186 #define lmask           0  /* unsigned int */
187
188 /*
189  * typedef enum inflate_mode consts, in inflate.h
190  */
191 #define INFLATE_MODE_TYPE 11  /* state->mode flags enum-ed in inflate.h */
192 #define INFLATE_MODE_BAD  26
193
194
195 #if ! defined( USE_MMX ) && ! defined( NO_MMX )
196
197 #define RUN_TIME_MMX
198
199 #define CHECK_MMX    1
200 #define DO_USE_MMX   2
201 #define DONT_USE_MMX 3
202
203 .globl inflate_fast_use_mmx
204
205 .data
206
207 .align 4,0
208 inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */
209 .long CHECK_MMX
210
211 #if defined( GAS_ELF )
212 /* elf info */
213 .type   inflate_fast_use_mmx,@object
214 .size   inflate_fast_use_mmx,4
215 #endif
216
217 #endif /* RUN_TIME_MMX */
218
219 #if defined( GAS_COFF )
220 /* coff info: scl 2 = extern, type 32 = function */
221 .def inflate_fast; .scl 2; .type 32; .endef
222 #endif
223
224 .text
225
226 .align 32,0x90
227 inflate_fast:
228         pushl   %edi
229         pushl   %esi
230         pushl   %ebp
231         pushl   %ebx
232         pushf   /* save eflags (strm_sp, state_sp assumes this is 32 bits) */
233         subl    $local_var_size, %esp
234         cld
235
236 #define strm_r  %esi
237 #define state_r %edi
238
239         movl    strm_sp(%esp), strm_r
240         movl    state_strm(strm_r), state_r
241
242         /* in = strm->next_in;
243          * out = strm->next_out;
244          * last = in + strm->avail_in - 11;
245          * beg = out - (start - strm->avail_out);
246          * end = out + (strm->avail_out - 257);
247          */
248         movl    avail_in_strm(strm_r), %edx
249         movl    next_in_strm(strm_r), %eax
250
251         addl    %eax, %edx      /* avail_in += next_in */
252         subl    $11, %edx       /* avail_in -= 11 */
253
254         movl    %eax, in(%esp)
255         movl    %edx, last(%esp)
256
257         movl    start_sp(%esp), %ebp
258         movl    avail_out_strm(strm_r), %ecx
259         movl    next_out_strm(strm_r), %ebx
260
261         subl    %ecx, %ebp      /* start -= avail_out */
262         negl    %ebp            /* start = -start */
263         addl    %ebx, %ebp      /* start += next_out */
264
265         subl    $257, %ecx      /* avail_out -= 257 */
266         addl    %ebx, %ecx      /* avail_out += out */
267
268         movl    %ebx, out(%esp)
269         movl    %ebp, beg(%esp)
270         movl    %ecx, end(%esp)
271
272         /* wsize = state->wsize;
273          * write = state->write;
274          * window = state->window;
275          * hold = state->hold;
276          * bits = state->bits;
277          * lcode = state->lencode;
278          * dcode = state->distcode;
279          * lmask = ( 1 << state->lenbits ) - 1;
280          * dmask = ( 1 << state->distbits ) - 1;
281          */
282
283         movl    lencode_state(state_r), %eax
284         movl    distcode_state(state_r), %ecx
285
286         movl    %eax, lcode(%esp)
287         movl    %ecx, dcode(%esp)
288
289         movl    $1, %eax
290         movl    lenbits_state(state_r), %ecx
291         shll    %cl, %eax
292         decl    %eax
293         movl    %eax, lmask(%esp)
294
295         movl    $1, %eax
296         movl    distbits_state(state_r), %ecx
297         shll    %cl, %eax
298         decl    %eax
299         movl    %eax, dmask(%esp)
300
301         movl    wsize_state(state_r), %eax
302         movl    write_state(state_r), %ecx
303         movl    window_state(state_r), %edx
304
305         movl    %eax, wsize(%esp)
306         movl    %ecx, write(%esp)
307         movl    %edx, window(%esp)
308
309         movl    hold_state(state_r), %ebp
310         movl    bits_state(state_r), %ebx
311
312 #undef strm_r
313 #undef state_r
314
315 #define in_r       %esi
316 #define from_r     %esi
317 #define out_r      %edi
318
319         movl    in(%esp), in_r
320         movl    last(%esp), %ecx
321         cmpl    in_r, %ecx
322         ja      .L_align_long           /* if in < last */
323
324         addl    $11, %ecx               /* ecx = &in[ avail_in ] */
325         subl    in_r, %ecx              /* ecx = avail_in */
326         movl    $12, %eax
327         subl    %ecx, %eax              /* eax = 12 - avail_in */
328         leal    buf(%esp), %edi
329         rep     movsb                   /* memcpy( buf, in, avail_in ) */
330         movl    %eax, %ecx
331         xorl    %eax, %eax
332         rep     stosb         /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */
333         leal    buf(%esp), in_r         /* in = buf */
334         movl    in_r, last(%esp)        /* last = in, do just one iteration */
335         jmp     .L_is_aligned
336
337         /* align in_r on long boundary */
338 .L_align_long:
339         testl   $3, in_r
340         jz      .L_is_aligned
341         xorl    %eax, %eax
342         movb    (in_r), %al
343         incl    in_r
344         movl    %ebx, %ecx
345         addl    $8, %ebx
346         shll    %cl, %eax
347         orl     %eax, %ebp
348         jmp     .L_align_long
349
350 .L_is_aligned:
351         movl    out(%esp), out_r
352
353 #if defined( NO_MMX )
354         jmp     .L_do_loop
355 #endif
356
357 #if defined( USE_MMX )
358         jmp     .L_init_mmx
359 #endif
360
361 /*** Runtime MMX check ***/
362
363 #if defined( RUN_TIME_MMX )
364 .L_check_mmx:
365         cmpl    $DO_USE_MMX, inflate_fast_use_mmx
366         je      .L_init_mmx
367         ja      .L_do_loop /* > 2 */
368
369         pushl   %eax
370         pushl   %ebx
371         pushl   %ecx
372         pushl   %edx
373         pushf
374         movl    (%esp), %eax      /* copy eflags to eax */
375         xorl    $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21)
376                                    * to see if cpu supports cpuid...
377                                    * ID bit method not supported by NexGen but
378                                    * bios may load a cpuid instruction and
379                                    * cpuid may be disabled on Cyrix 5-6x86 */
380         popf
381         pushf
382         popl    %edx              /* copy new eflags to edx */
383         xorl    %eax, %edx        /* test if ID bit is flipped */
384         jz      .L_dont_use_mmx   /* not flipped if zero */
385         xorl    %eax, %eax
386         cpuid
387         cmpl    $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */
388         jne     .L_dont_use_mmx
389         cmpl    $0x6c65746e, %ecx
390         jne     .L_dont_use_mmx
391         cmpl    $0x49656e69, %edx
392         jne     .L_dont_use_mmx
393         movl    $1, %eax
394         cpuid                     /* get cpu features */
395         shrl    $8, %eax
396         andl    $15, %eax
397         cmpl    $6, %eax          /* check for Pentium family, is 0xf for P4 */
398         jne     .L_dont_use_mmx
399         testl   $0x800000, %edx   /* test if MMX feature is set (bit 23) */
400         jnz     .L_use_mmx
401         jmp     .L_dont_use_mmx
402 .L_use_mmx:
403         movl    $DO_USE_MMX, inflate_fast_use_mmx
404         jmp     .L_check_mmx_pop
405 .L_dont_use_mmx:
406         movl    $DONT_USE_MMX, inflate_fast_use_mmx
407 .L_check_mmx_pop:
408         popl    %edx
409         popl    %ecx
410         popl    %ebx
411         popl    %eax
412         jmp     .L_check_mmx
413 #endif
414
415
416 /*** Non-MMX code ***/
417
418 #if defined ( NO_MMX ) || defined( RUN_TIME_MMX )
419
420 #define hold_r     %ebp
421 #define bits_r     %bl
422 #define bitslong_r %ebx
423
424 .align 32,0x90
425 .L_while_test:
426         /* while (in < last && out < end)
427          */
428         cmpl    out_r, end(%esp)
429         jbe     .L_break_loop           /* if (out >= end) */
430
431         cmpl    in_r, last(%esp)
432         jbe     .L_break_loop
433
434 .L_do_loop:
435         /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
436          *
437          * do {
438          *   if (bits < 15) {
439          *     hold |= *((unsigned short *)in)++ << bits;
440          *     bits += 16
441          *   }
442          *   this = lcode[hold & lmask]
443          */
444         cmpb    $15, bits_r
445         ja      .L_get_length_code      /* if (15 < bits) */
446
447         xorl    %eax, %eax
448         lodsw                           /* al = *(ushort *)in++ */
449         movb    bits_r, %cl             /* cl = bits, needs it for shifting */
450         addb    $16, bits_r             /* bits += 16 */
451         shll    %cl, %eax
452         orl     %eax, hold_r            /* hold |= *((ushort *)in)++ << bits */
453
454 .L_get_length_code:
455         movl    lmask(%esp), %edx       /* edx = lmask */
456         movl    lcode(%esp), %ecx       /* ecx = lcode */
457         andl    hold_r, %edx            /* edx &= hold */
458         movl    (%ecx,%edx,4), %eax     /* eax = lcode[hold & lmask] */
459
460 .L_dolen:
461         /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
462          *
463          * dolen:
464          *    bits -= this.bits;
465          *    hold >>= this.bits
466          */
467         movb    %ah, %cl                /* cl = this.bits */
468         subb    %ah, bits_r             /* bits -= this.bits */
469         shrl    %cl, hold_r             /* hold >>= this.bits */
470
471         /* check if op is a literal
472          * if (op == 0) {
473          *    PUP(out) = this.val;
474          *  }
475          */
476         testb   %al, %al
477         jnz     .L_test_for_length_base /* if (op != 0) 45.7% */
478
479         shrl    $16, %eax               /* output this.val char */
480         stosb
481         jmp     .L_while_test
482
483 .L_test_for_length_base:
484         /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len
485          *
486          * else if (op & 16) {
487          *   len = this.val
488          *   op &= 15
489          *   if (op) {
490          *     if (op > bits) {
491          *       hold |= *((unsigned short *)in)++ << bits;
492          *       bits += 16
493          *     }
494          *     len += hold & mask[op];
495          *     bits -= op;
496          *     hold >>= op;
497          *   }
498          */
499 #define len_r %edx
500         movl    %eax, len_r             /* len = this */
501         shrl    $16, len_r              /* len = this.val */
502         movb    %al, %cl
503
504         testb   $16, %al
505         jz      .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */
506         andb    $15, %cl                /* op &= 15 */
507         jz      .L_save_len             /* if (!op) */
508         cmpb    %cl, bits_r
509         jae     .L_add_bits_to_len      /* if (op <= bits) */
510
511         movb    %cl, %ch                /* stash op in ch, freeing cl */
512         xorl    %eax, %eax
513         lodsw                           /* al = *(ushort *)in++ */
514         movb    bits_r, %cl             /* cl = bits, needs it for shifting */
515         addb    $16, bits_r             /* bits += 16 */
516         shll    %cl, %eax
517         orl     %eax, hold_r            /* hold |= *((ushort *)in)++ << bits */
518         movb    %ch, %cl                /* move op back to ecx */
519
520 .L_add_bits_to_len:
521         movl    $1, %eax
522         shll    %cl, %eax
523         decl    %eax
524         subb    %cl, bits_r
525         andl    hold_r, %eax            /* eax &= hold */
526         shrl    %cl, hold_r
527         addl    %eax, len_r             /* len += hold & mask[op] */
528
529 .L_save_len:
530         movl    len_r, len(%esp)        /* save len */
531 #undef  len_r
532
533 .L_decode_distance:
534         /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist
535          *
536          *   if (bits < 15) {
537          *     hold |= *((unsigned short *)in)++ << bits;
538          *     bits += 16
539          *   }
540          *   this = dcode[hold & dmask];
541          * dodist:
542          *   bits -= this.bits;
543          *   hold >>= this.bits;
544          *   op = this.op;
545          */
546
547         cmpb    $15, bits_r
548         ja      .L_get_distance_code    /* if (15 < bits) */
549
550         xorl    %eax, %eax
551         lodsw                           /* al = *(ushort *)in++ */
552         movb    bits_r, %cl             /* cl = bits, needs it for shifting */
553         addb    $16, bits_r             /* bits += 16 */
554         shll    %cl, %eax
555         orl     %eax, hold_r            /* hold |= *((ushort *)in)++ << bits */
556
557 .L_get_distance_code:
558         movl    dmask(%esp), %edx       /* edx = dmask */
559         movl    dcode(%esp), %ecx       /* ecx = dcode */
560         andl    hold_r, %edx            /* edx &= hold */
561         movl    (%ecx,%edx,4), %eax     /* eax = dcode[hold & dmask] */
562
563 #define dist_r %edx
564 .L_dodist:
565         movl    %eax, dist_r            /* dist = this */
566         shrl    $16, dist_r             /* dist = this.val */
567         movb    %ah, %cl
568         subb    %ah, bits_r             /* bits -= this.bits */
569         shrl    %cl, hold_r             /* hold >>= this.bits */
570
571         /* if (op & 16) {
572          *   dist = this.val
573          *   op &= 15
574          *   if (op > bits) {
575          *     hold |= *((unsigned short *)in)++ << bits;
576          *     bits += 16
577          *   }
578          *   dist += hold & mask[op];
579          *   bits -= op;
580          *   hold >>= op;
581          */
582         movb    %al, %cl                /* cl = this.op */
583
584         testb   $16, %al                /* if ((op & 16) == 0) */
585         jz      .L_test_for_second_level_dist
586         andb    $15, %cl                /* op &= 15 */
587         jz      .L_check_dist_one
588         cmpb    %cl, bits_r
589         jae     .L_add_bits_to_dist     /* if (op <= bits) 97.6% */
590
591         movb    %cl, %ch                /* stash op in ch, freeing cl */
592         xorl    %eax, %eax
593         lodsw                           /* al = *(ushort *)in++ */
594         movb    bits_r, %cl             /* cl = bits, needs it for shifting */
595         addb    $16, bits_r             /* bits += 16 */
596         shll    %cl, %eax
597         orl     %eax, hold_r            /* hold |= *((ushort *)in)++ << bits */
598         movb    %ch, %cl                /* move op back to ecx */
599
600 .L_add_bits_to_dist:
601         movl    $1, %eax
602         shll    %cl, %eax
603         decl    %eax                    /* (1 << op) - 1 */
604         subb    %cl, bits_r
605         andl    hold_r, %eax            /* eax &= hold */
606         shrl    %cl, hold_r
607         addl    %eax, dist_r            /* dist += hold & ((1 << op) - 1) */
608         jmp     .L_check_window
609
610 .L_check_window:
611         /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
612          *       %ecx = nbytes
613          *
614          * nbytes = out - beg;
615          * if (dist <= nbytes) {
616          *   from = out - dist;
617          *   do {
618          *     PUP(out) = PUP(from);
619          *   } while (--len > 0) {
620          * }
621          */
622
623         movl    in_r, in(%esp)          /* save in so from can use it's reg */
624         movl    out_r, %eax
625         subl    beg(%esp), %eax         /* nbytes = out - beg */
626
627         cmpl    dist_r, %eax
628         jb      .L_clip_window          /* if (dist > nbytes) 4.2% */
629
630         movl    len(%esp), %ecx
631         movl    out_r, from_r
632         subl    dist_r, from_r          /* from = out - dist */
633
634         subl    $3, %ecx
635         movb    (from_r), %al
636         movb    %al, (out_r)
637         movb    1(from_r), %al
638         movb    2(from_r), %dl
639         addl    $3, from_r
640         movb    %al, 1(out_r)
641         movb    %dl, 2(out_r)
642         addl    $3, out_r
643         rep     movsb
644
645         movl    in(%esp), in_r          /* move in back to %esi, toss from */
646         jmp     .L_while_test
647
648 .align 16,0x90
649 .L_check_dist_one:
650         cmpl    $1, dist_r
651         jne     .L_check_window
652         cmpl    out_r, beg(%esp)
653         je      .L_check_window
654
655         decl    out_r
656         movl    len(%esp), %ecx
657         movb    (out_r), %al
658         subl    $3, %ecx
659
660         movb    %al, 1(out_r)
661         movb    %al, 2(out_r)
662         movb    %al, 3(out_r)
663         addl    $4, out_r
664         rep     stosb
665
666         jmp     .L_while_test
667
668 .align 16,0x90
669 .L_test_for_second_level_length:
670         /* else if ((op & 64) == 0) {
671          *   this = lcode[this.val + (hold & mask[op])];
672          * }
673          */
674         testb   $64, %al
675         jnz     .L_test_for_end_of_block  /* if ((op & 64) != 0) */
676
677         movl    $1, %eax
678         shll    %cl, %eax
679         decl    %eax
680         andl    hold_r, %eax            /* eax &= hold */
681         addl    %edx, %eax              /* eax += this.val */
682         movl    lcode(%esp), %edx       /* edx = lcode */
683         movl    (%edx,%eax,4), %eax     /* eax = lcode[val + (hold&mask[op])] */
684         jmp     .L_dolen
685
686 .align 16,0x90
687 .L_test_for_second_level_dist:
688         /* else if ((op & 64) == 0) {
689          *   this = dcode[this.val + (hold & mask[op])];
690          * }
691          */
692         testb   $64, %al
693         jnz     .L_invalid_distance_code  /* if ((op & 64) != 0) */
694
695         movl    $1, %eax
696         shll    %cl, %eax
697         decl    %eax
698         andl    hold_r, %eax            /* eax &= hold */
699         addl    %edx, %eax              /* eax += this.val */
700         movl    dcode(%esp), %edx       /* edx = dcode */
701         movl    (%edx,%eax,4), %eax     /* eax = dcode[val + (hold&mask[op])] */
702         jmp     .L_dodist
703
704 .align 16,0x90
705 .L_clip_window:
706         /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
707          *       %ecx = nbytes
708          *
709          * else {
710          *   if (dist > wsize) {
711          *     invalid distance
712          *   }
713          *   from = window;
714          *   nbytes = dist - nbytes;
715          *   if (write == 0) {
716          *     from += wsize - nbytes;
717          */
718 #define nbytes_r %ecx
719         movl    %eax, nbytes_r
720         movl    wsize(%esp), %eax       /* prepare for dist compare */
721         negl    nbytes_r                /* nbytes = -nbytes */
722         movl    window(%esp), from_r    /* from = window */
723
724         cmpl    dist_r, %eax
725         jb      .L_invalid_distance_too_far /* if (dist > wsize) */
726
727         addl    dist_r, nbytes_r        /* nbytes = dist - nbytes */
728         cmpl    $0, write(%esp)
729         jne     .L_wrap_around_window   /* if (write != 0) */
730
731         subl    nbytes_r, %eax
732         addl    %eax, from_r            /* from += wsize - nbytes */
733
734         /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
735          *       %ecx = nbytes, %eax = len
736          *
737          *     if (nbytes < len) {
738          *       len -= nbytes;
739          *       do {
740          *         PUP(out) = PUP(from);
741          *       } while (--nbytes);
742          *       from = out - dist;
743          *     }
744          *   }
745          */
746 #define len_r %eax
747         movl    len(%esp), len_r
748         cmpl    nbytes_r, len_r
749         jbe     .L_do_copy1             /* if (nbytes >= len) */
750
751         subl    nbytes_r, len_r         /* len -= nbytes */
752         rep     movsb
753         movl    out_r, from_r
754         subl    dist_r, from_r          /* from = out - dist */
755         jmp     .L_do_copy1
756
757         cmpl    nbytes_r, len_r
758         jbe     .L_do_copy1             /* if (nbytes >= len) */
759
760         subl    nbytes_r, len_r         /* len -= nbytes */
761         rep     movsb
762         movl    out_r, from_r
763         subl    dist_r, from_r          /* from = out - dist */
764         jmp     .L_do_copy1
765
766 .L_wrap_around_window:
767         /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
768          *       %ecx = nbytes, %eax = write, %eax = len
769          *
770          *   else if (write < nbytes) {
771          *     from += wsize + write - nbytes;
772          *     nbytes -= write;
773          *     if (nbytes < len) {
774          *       len -= nbytes;
775          *       do {
776          *         PUP(out) = PUP(from);
777          *       } while (--nbytes);
778          *       from = window;
779          *       nbytes = write;
780          *       if (nbytes < len) {
781          *         len -= nbytes;
782          *         do {
783          *           PUP(out) = PUP(from);
784          *         } while(--nbytes);
785          *         from = out - dist;
786          *       }
787          *     }
788          *   }
789          */
790 #define write_r %eax
791         movl    write(%esp), write_r
792         cmpl    write_r, nbytes_r
793         jbe     .L_contiguous_in_window /* if (write >= nbytes) */
794
795         addl    wsize(%esp), from_r
796         addl    write_r, from_r
797         subl    nbytes_r, from_r        /* from += wsize + write - nbytes */
798         subl    write_r, nbytes_r       /* nbytes -= write */
799 #undef write_r
800
801         movl    len(%esp), len_r
802         cmpl    nbytes_r, len_r
803         jbe     .L_do_copy1             /* if (nbytes >= len) */
804
805         subl    nbytes_r, len_r         /* len -= nbytes */
806         rep     movsb
807         movl    window(%esp), from_r    /* from = window */
808         movl    write(%esp), nbytes_r   /* nbytes = write */
809         cmpl    nbytes_r, len_r
810         jbe     .L_do_copy1             /* if (nbytes >= len) */
811
812         subl    nbytes_r, len_r         /* len -= nbytes */
813         rep     movsb
814         movl    out_r, from_r
815         subl    dist_r, from_r          /* from = out - dist */
816         jmp     .L_do_copy1
817
818 .L_contiguous_in_window:
819         /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
820          *       %ecx = nbytes, %eax = write, %eax = len
821          *
822          *   else {
823          *     from += write - nbytes;
824          *     if (nbytes < len) {
825          *       len -= nbytes;
826          *       do {
827          *         PUP(out) = PUP(from);
828          *       } while (--nbytes);
829          *       from = out - dist;
830          *     }
831          *   }
832          */
833 #define write_r %eax
834         addl    write_r, from_r
835         subl    nbytes_r, from_r        /* from += write - nbytes */
836 #undef write_r
837
838         movl    len(%esp), len_r
839         cmpl    nbytes_r, len_r
840         jbe     .L_do_copy1             /* if (nbytes >= len) */
841
842         subl    nbytes_r, len_r         /* len -= nbytes */
843         rep     movsb
844         movl    out_r, from_r
845         subl    dist_r, from_r          /* from = out - dist */
846
847 .L_do_copy1:
848         /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out
849          *       %eax = len
850          *
851          *     while (len > 0) {
852          *       PUP(out) = PUP(from);
853          *       len--;
854          *     }
855          *   }
856          * } while (in < last && out < end);
857          */
858 #undef nbytes_r
859 #define in_r %esi
860         movl    len_r, %ecx
861         rep     movsb
862
863         movl    in(%esp), in_r          /* move in back to %esi, toss from */
864         jmp     .L_while_test
865
866 #undef len_r
867 #undef dist_r
868
869 #endif /* NO_MMX || RUN_TIME_MMX */
870
871
872 /*** MMX code ***/
873
874 #if defined( USE_MMX ) || defined( RUN_TIME_MMX )
875
876 .align 32,0x90
877 .L_init_mmx:
878         emms
879
880 #undef  bits_r
881 #undef  bitslong_r
882 #define bitslong_r %ebp
883 #define hold_mm    %mm0
884         movd    %ebp, hold_mm
885         movl    %ebx, bitslong_r
886
887 #define used_mm   %mm1
888 #define dmask2_mm %mm2
889 #define lmask2_mm %mm3
890 #define lmask_mm  %mm4
891 #define dmask_mm  %mm5
892 #define tmp_mm    %mm6
893
894         movd    lmask(%esp), lmask_mm
895         movq    lmask_mm, lmask2_mm
896         movd    dmask(%esp), dmask_mm
897         movq    dmask_mm, dmask2_mm
898         pxor    used_mm, used_mm
899         movl    lcode(%esp), %ebx       /* ebx = lcode */
900         jmp     .L_do_loop_mmx
901
902 .align 32,0x90
903 .L_while_test_mmx:
904         /* while (in < last && out < end)
905          */
906         cmpl    out_r, end(%esp)
907         jbe     .L_break_loop           /* if (out >= end) */
908
909         cmpl    in_r, last(%esp)
910         jbe     .L_break_loop
911
912 .L_do_loop_mmx:
913         psrlq   used_mm, hold_mm        /* hold_mm >>= last bit length */
914
915         cmpl    $32, bitslong_r
916         ja      .L_get_length_code_mmx  /* if (32 < bits) */
917
918         movd    bitslong_r, tmp_mm
919         movd    (in_r), %mm7
920         addl    $4, in_r
921         psllq   tmp_mm, %mm7
922         addl    $32, bitslong_r
923         por     %mm7, hold_mm           /* hold_mm |= *((uint *)in)++ << bits */
924
925 .L_get_length_code_mmx:
926         pand    hold_mm, lmask_mm
927         movd    lmask_mm, %eax
928         movq    lmask2_mm, lmask_mm
929         movl    (%ebx,%eax,4), %eax     /* eax = lcode[hold & lmask] */
930
931 .L_dolen_mmx:
932         movzbl  %ah, %ecx               /* ecx = this.bits */
933         movd    %ecx, used_mm
934         subl    %ecx, bitslong_r        /* bits -= this.bits */
935
936         testb   %al, %al
937         jnz     .L_test_for_length_base_mmx /* if (op != 0) 45.7% */
938
939         shrl    $16, %eax               /* output this.val char */
940         stosb
941         jmp     .L_while_test_mmx
942
943 .L_test_for_length_base_mmx:
944 #define len_r  %edx
945         movl    %eax, len_r             /* len = this */
946         shrl    $16, len_r              /* len = this.val */
947
948         testb   $16, %al
949         jz      .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */
950         andl    $15, %eax               /* op &= 15 */
951         jz      .L_decode_distance_mmx  /* if (!op) */
952
953         psrlq   used_mm, hold_mm        /* hold_mm >>= last bit length */
954         movd    %eax, used_mm
955         movd    hold_mm, %ecx
956         subl    %eax, bitslong_r
957         andl    .L_mask(,%eax,4), %ecx
958         addl    %ecx, len_r             /* len += hold & mask[op] */
959
960 .L_decode_distance_mmx:
961         psrlq   used_mm, hold_mm        /* hold_mm >>= last bit length */
962
963         cmpl    $32, bitslong_r
964         ja      .L_get_dist_code_mmx    /* if (32 < bits) */
965
966         movd    bitslong_r, tmp_mm
967         movd    (in_r), %mm7
968         addl    $4, in_r
969         psllq   tmp_mm, %mm7
970         addl    $32, bitslong_r
971         por     %mm7, hold_mm           /* hold_mm |= *((uint *)in)++ << bits */
972
973 .L_get_dist_code_mmx:
974         movl    dcode(%esp), %ebx       /* ebx = dcode */
975         pand    hold_mm, dmask_mm
976         movd    dmask_mm, %eax
977         movq    dmask2_mm, dmask_mm
978         movl    (%ebx,%eax,4), %eax     /* eax = dcode[hold & lmask] */
979
980 .L_dodist_mmx:
981 #define dist_r %ebx
982         movzbl  %ah, %ecx               /* ecx = this.bits */
983         movl    %eax, dist_r
984         shrl    $16, dist_r             /* dist  = this.val */
985         subl    %ecx, bitslong_r        /* bits -= this.bits */
986         movd    %ecx, used_mm
987
988         testb   $16, %al                /* if ((op & 16) == 0) */
989         jz      .L_test_for_second_level_dist_mmx
990         andl    $15, %eax               /* op &= 15 */
991         jz      .L_check_dist_one_mmx
992
993 .L_add_bits_to_dist_mmx:
994         psrlq   used_mm, hold_mm        /* hold_mm >>= last bit length */
995         movd    %eax, used_mm           /* save bit length of current op */
996         movd    hold_mm, %ecx           /* get the next bits on input stream */
997         subl    %eax, bitslong_r        /* bits -= op bits */
998         andl    .L_mask(,%eax,4), %ecx  /* ecx   = hold & mask[op] */
999         addl    %ecx, dist_r            /* dist += hold & mask[op] */
1000
1001 .L_check_window_mmx:
1002         movl    in_r, in(%esp)          /* save in so from can use it's reg */
1003         movl    out_r, %eax
1004         subl    beg(%esp), %eax         /* nbytes = out - beg */
1005
1006         cmpl    dist_r, %eax
1007         jb      .L_clip_window_mmx      /* if (dist > nbytes) 4.2% */
1008
1009         movl    len_r, %ecx
1010         movl    out_r, from_r
1011         subl    dist_r, from_r          /* from = out - dist */
1012
1013         subl    $3, %ecx
1014         movb    (from_r), %al
1015         movb    %al, (out_r)
1016         movb    1(from_r), %al
1017         movb    2(from_r), %dl
1018         addl    $3, from_r
1019         movb    %al, 1(out_r)
1020         movb    %dl, 2(out_r)
1021         addl    $3, out_r
1022         rep     movsb
1023
1024         movl    in(%esp), in_r          /* move in back to %esi, toss from */
1025         movl    lcode(%esp), %ebx       /* move lcode back to %ebx, toss dist */
1026         jmp     .L_while_test_mmx
1027
1028 .align 16,0x90
1029 .L_check_dist_one_mmx:
1030         cmpl    $1, dist_r
1031         jne     .L_check_window_mmx
1032         cmpl    out_r, beg(%esp)
1033         je      .L_check_window_mmx
1034
1035         decl    out_r
1036         movl    len_r, %ecx
1037         movb    (out_r), %al
1038         subl    $3, %ecx
1039
1040         movb    %al, 1(out_r)
1041         movb    %al, 2(out_r)
1042         movb    %al, 3(out_r)
1043         addl    $4, out_r
1044         rep     stosb
1045
1046         movl    lcode(%esp), %ebx       /* move lcode back to %ebx, toss dist */
1047         jmp     .L_while_test_mmx
1048
1049 .align 16,0x90
1050 .L_test_for_second_level_length_mmx:
1051         testb   $64, %al
1052         jnz     .L_test_for_end_of_block  /* if ((op & 64) != 0) */
1053
1054         andl    $15, %eax
1055         psrlq   used_mm, hold_mm        /* hold_mm >>= last bit length */
1056         movd    hold_mm, %ecx
1057         andl    .L_mask(,%eax,4), %ecx
1058         addl    len_r, %ecx
1059         movl    (%ebx,%ecx,4), %eax     /* eax = lcode[hold & lmask] */
1060         jmp     .L_dolen_mmx
1061
1062 .align 16,0x90
1063 .L_test_for_second_level_dist_mmx:
1064         testb   $64, %al
1065         jnz     .L_invalid_distance_code  /* if ((op & 64) != 0) */
1066
1067         andl    $15, %eax
1068         psrlq   used_mm, hold_mm        /* hold_mm >>= last bit length */
1069         movd    hold_mm, %ecx
1070         andl    .L_mask(,%eax,4), %ecx
1071         movl    dcode(%esp), %eax       /* ecx = dcode */
1072         addl    dist_r, %ecx
1073         movl    (%eax,%ecx,4), %eax     /* eax = lcode[hold & lmask] */
1074         jmp     .L_dodist_mmx
1075
1076 .align 16,0x90
1077 .L_clip_window_mmx:
1078 #define nbytes_r %ecx
1079         movl    %eax, nbytes_r
1080         movl    wsize(%esp), %eax       /* prepare for dist compare */
1081         negl    nbytes_r                /* nbytes = -nbytes */
1082         movl    window(%esp), from_r    /* from = window */
1083
1084         cmpl    dist_r, %eax
1085         jb      .L_invalid_distance_too_far /* if (dist > wsize) */
1086
1087         addl    dist_r, nbytes_r        /* nbytes = dist - nbytes */
1088         cmpl    $0, write(%esp)
1089         jne     .L_wrap_around_window_mmx /* if (write != 0) */
1090
1091         subl    nbytes_r, %eax
1092         addl    %eax, from_r            /* from += wsize - nbytes */
1093
1094         cmpl    nbytes_r, len_r
1095         jbe     .L_do_copy1_mmx         /* if (nbytes >= len) */
1096
1097         subl    nbytes_r, len_r         /* len -= nbytes */
1098         rep     movsb
1099         movl    out_r, from_r
1100         subl    dist_r, from_r          /* from = out - dist */
1101         jmp     .L_do_copy1_mmx
1102
1103         cmpl    nbytes_r, len_r
1104         jbe     .L_do_copy1_mmx         /* if (nbytes >= len) */
1105
1106         subl    nbytes_r, len_r         /* len -= nbytes */
1107         rep     movsb
1108         movl    out_r, from_r
1109         subl    dist_r, from_r          /* from = out - dist */
1110         jmp     .L_do_copy1_mmx
1111
1112 .L_wrap_around_window_mmx:
1113 #define write_r %eax
1114         movl    write(%esp), write_r
1115         cmpl    write_r, nbytes_r
1116         jbe     .L_contiguous_in_window_mmx /* if (write >= nbytes) */
1117
1118         addl    wsize(%esp), from_r
1119         addl    write_r, from_r
1120         subl    nbytes_r, from_r        /* from += wsize + write - nbytes */
1121         subl    write_r, nbytes_r       /* nbytes -= write */
1122 #undef write_r
1123
1124         cmpl    nbytes_r, len_r
1125         jbe     .L_do_copy1_mmx         /* if (nbytes >= len) */
1126
1127         subl    nbytes_r, len_r         /* len -= nbytes */
1128         rep     movsb
1129         movl    window(%esp), from_r    /* from = window */
1130         movl    write(%esp), nbytes_r   /* nbytes = write */
1131         cmpl    nbytes_r, len_r
1132         jbe     .L_do_copy1_mmx         /* if (nbytes >= len) */
1133
1134         subl    nbytes_r, len_r         /* len -= nbytes */
1135         rep     movsb
1136         movl    out_r, from_r
1137         subl    dist_r, from_r          /* from = out - dist */
1138         jmp     .L_do_copy1_mmx
1139
1140 .L_contiguous_in_window_mmx:
1141 #define write_r %eax
1142         addl    write_r, from_r
1143         subl    nbytes_r, from_r        /* from += write - nbytes */
1144 #undef write_r
1145
1146         cmpl    nbytes_r, len_r
1147         jbe     .L_do_copy1_mmx         /* if (nbytes >= len) */
1148
1149         subl    nbytes_r, len_r         /* len -= nbytes */
1150         rep     movsb
1151         movl    out_r, from_r
1152         subl    dist_r, from_r          /* from = out - dist */
1153
1154 .L_do_copy1_mmx:
1155 #undef nbytes_r
1156 #define in_r %esi
1157         movl    len_r, %ecx
1158         rep     movsb
1159
1160         movl    in(%esp), in_r          /* move in back to %esi, toss from */
1161         movl    lcode(%esp), %ebx       /* move lcode back to %ebx, toss dist */
1162         jmp     .L_while_test_mmx
1163
1164 #undef hold_r
1165 #undef bitslong_r
1166
1167 #endif /* USE_MMX || RUN_TIME_MMX */
1168
1169
1170 /*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/
1171
1172 .L_invalid_distance_code:
1173         /* else {
1174          *   strm->msg = "invalid distance code";
1175          *   state->mode = BAD;
1176          * }
1177          */
1178         movl    $.L_invalid_distance_code_msg, %ecx
1179         movl    $INFLATE_MODE_BAD, %edx
1180         jmp     .L_update_stream_state
1181
1182 .L_test_for_end_of_block:
1183         /* else if (op & 32) {
1184          *   state->mode = TYPE;
1185          *   break;
1186          * }
1187          */
1188         testb   $32, %al
1189         jz      .L_invalid_literal_length_code  /* if ((op & 32) == 0) */
1190
1191         movl    $0, %ecx
1192         movl    $INFLATE_MODE_TYPE, %edx
1193         jmp     .L_update_stream_state
1194
1195 .L_invalid_literal_length_code:
1196         /* else {
1197          *   strm->msg = "invalid literal/length code";
1198          *   state->mode = BAD;
1199          * }
1200          */
1201         movl    $.L_invalid_literal_length_code_msg, %ecx
1202         movl    $INFLATE_MODE_BAD, %edx
1203         jmp     .L_update_stream_state
1204
1205 .L_invalid_distance_too_far:
1206         /* strm->msg = "invalid distance too far back";
1207          * state->mode = BAD;
1208          */
1209         movl    in(%esp), in_r          /* from_r has in's reg, put in back */
1210         movl    $.L_invalid_distance_too_far_msg, %ecx
1211         movl    $INFLATE_MODE_BAD, %edx
1212         jmp     .L_update_stream_state
1213
1214 .L_update_stream_state:
1215         /* set strm->msg = %ecx, strm->state->mode = %edx */
1216         movl    strm_sp(%esp), %eax
1217         testl   %ecx, %ecx              /* if (msg != NULL) */
1218         jz      .L_skip_msg
1219         movl    %ecx, msg_strm(%eax)    /* strm->msg = msg */
1220 .L_skip_msg:
1221         movl    state_strm(%eax), %eax  /* state = strm->state */
1222         movl    %edx, mode_state(%eax)  /* state->mode = edx (BAD | TYPE) */
1223         jmp     .L_break_loop
1224
1225 .align 32,0x90
1226 .L_break_loop:
1227
1228 /*
1229  * Regs:
1230  *
1231  * bits = %ebp when mmx, and in %ebx when non-mmx
1232  * hold = %hold_mm when mmx, and in %ebp when non-mmx
1233  * in   = %esi
1234  * out  = %edi
1235  */
1236
1237 #if defined( USE_MMX ) || defined( RUN_TIME_MMX )
1238
1239 #if defined( RUN_TIME_MMX )
1240
1241         cmpl    $DO_USE_MMX, inflate_fast_use_mmx
1242         jne     .L_update_next_in
1243
1244 #endif /* RUN_TIME_MMX */
1245
1246         movl    %ebp, %ebx
1247
1248 .L_update_next_in:
1249
1250 #endif
1251
1252 #define strm_r  %eax
1253 #define state_r %edx
1254
1255         /* len = bits >> 3;
1256          * in -= len;
1257          * bits -= len << 3;
1258          * hold &= (1U << bits) - 1;
1259          * state->hold = hold;
1260          * state->bits = bits;
1261          * strm->next_in = in;
1262          * strm->next_out = out;
1263          */
1264         movl    strm_sp(%esp), strm_r
1265         movl    %ebx, %ecx
1266         movl    state_strm(strm_r), state_r
1267         shrl    $3, %ecx
1268         subl    %ecx, in_r
1269         shll    $3, %ecx
1270         subl    %ecx, %ebx
1271         movl    out_r, next_out_strm(strm_r)
1272         movl    %ebx, bits_state(state_r)
1273         movl    %ebx, %ecx
1274
1275         leal    buf(%esp), %ebx
1276         cmpl    %ebx, last(%esp)
1277         jne     .L_buf_not_used         /* if buf != last */
1278
1279         subl    %ebx, in_r              /* in -= buf */
1280         movl    next_in_strm(strm_r), %ebx
1281         movl    %ebx, last(%esp)        /* last = strm->next_in */
1282         addl    %ebx, in_r              /* in += strm->next_in */
1283         movl    avail_in_strm(strm_r), %ebx
1284         subl    $11, %ebx
1285         addl    %ebx, last(%esp)    /* last = &strm->next_in[ avail_in - 11 ] */
1286
1287 .L_buf_not_used:
1288         movl    in_r, next_in_strm(strm_r)
1289
1290         movl    $1, %ebx
1291         shll    %cl, %ebx
1292         decl    %ebx
1293
1294 #if defined( USE_MMX ) || defined( RUN_TIME_MMX )
1295
1296 #if defined( RUN_TIME_MMX )
1297
1298         cmpl    $DO_USE_MMX, inflate_fast_use_mmx
1299         jne     .L_update_hold
1300
1301 #endif /* RUN_TIME_MMX */
1302
1303         psrlq   used_mm, hold_mm        /* hold_mm >>= last bit length */
1304         movd    hold_mm, %ebp
1305
1306         emms
1307
1308 .L_update_hold:
1309
1310 #endif /* USE_MMX || RUN_TIME_MMX */
1311
1312         andl    %ebx, %ebp
1313         movl    %ebp, hold_state(state_r)
1314
1315 #define last_r %ebx
1316
1317         /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */
1318         movl    last(%esp), last_r
1319         cmpl    in_r, last_r
1320         jbe     .L_last_is_smaller     /* if (in >= last) */
1321
1322         subl    in_r, last_r           /* last -= in */
1323         addl    $11, last_r            /* last += 11 */
1324         movl    last_r, avail_in_strm(strm_r)
1325         jmp     .L_fixup_out
1326 .L_last_is_smaller:
1327         subl    last_r, in_r           /* in -= last */
1328         negl    in_r                   /* in = -in */
1329         addl    $11, in_r              /* in += 11 */
1330         movl    in_r, avail_in_strm(strm_r)
1331
1332 #undef last_r
1333 #define end_r %ebx
1334
1335 .L_fixup_out:
1336         /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/
1337         movl    end(%esp), end_r
1338         cmpl    out_r, end_r
1339         jbe     .L_end_is_smaller      /* if (out >= end) */
1340
1341         subl    out_r, end_r           /* end -= out */
1342         addl    $257, end_r            /* end += 257 */
1343         movl    end_r, avail_out_strm(strm_r)
1344         jmp     .L_done
1345 .L_end_is_smaller:
1346         subl    end_r, out_r           /* out -= end */
1347         negl    out_r                  /* out = -out */
1348         addl    $257, out_r            /* out += 257 */
1349         movl    out_r, avail_out_strm(strm_r)
1350
1351 #undef end_r
1352 #undef strm_r
1353 #undef state_r
1354
1355 .L_done:
1356         addl    $local_var_size, %esp
1357         popf
1358         popl    %ebx
1359         popl    %ebp
1360         popl    %esi
1361         popl    %edi
1362         ret
1363
1364 #if defined( GAS_ELF )
1365 /* elf info */
1366 .type inflate_fast,@function
1367 .size inflate_fast,.-inflate_fast
1368 #endif