Merge branch 'master' of ssh://git.samba.org/data/git/samba into regsrv
[kai/samba-autobuild/.git] / lib / zlib / contrib / masmx86 / gvmat32.asm
1 ; gvmat32.asm -- Asm portion of the optimized longest_match for 32 bits x86\r
2 ; Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant.\r
3 ; File written by Gilles Vollant, by modifiying the longest_match\r
4 ;  from Jean-loup Gailly in deflate.c\r
5 ;\r
6 ;         http://www.zlib.net\r
7 ;         http://www.winimage.com/zLibDll\r
8 ;         http://www.muppetlabs.com/~breadbox/software/assembly.html\r
9 ;\r
10 ; For Visual C++ 4.x and higher and ML 6.x and higher\r
11 ;   ml.exe is in directory \MASM611C of Win95 DDK\r
12 ;   ml.exe is also distributed in http://www.masm32.com/masmdl.htm\r
13 ;    and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/\r
14 ;\r
15 ; this file contain two implementation of longest_match\r
16 ;\r
17 ;  longest_match_7fff : written 1996 by Gilles Vollant optimized for \r
18 ;            first Pentium. Assume s->w_mask == 0x7fff\r
19 ;  longest_match_686 : written by Brian raiter (1998), optimized for Pentium Pro\r
20 ;\r
21 ;  for using an seembly version of longest_match, you need define ASMV in project\r
22 ;  There is two way in using gvmat32.asm\r
23 ;\r
24 ;  A) Suggested method\r
25 ;    if you want include both longest_match_7fff and longest_match_686\r
26 ;    compile the asm file running\r
27 ;           ml /coff /Zi /Flgvmat32.lst /c gvmat32.asm\r
28 ;    and include gvmat32c.c in your project\r
29 ;    if you have an old cpu (386,486 or first Pentium) and s->w_mask==0x7fff,\r
30 ;        longest_match_7fff will be used\r
31 ;    if you have a more modern CPU (Pentium Pro, II and higher)\r
32 ;        longest_match_686 will be used\r
33 ;    on old cpu with s->w_mask!=0x7fff, longest_match_686 will be used,\r
34 ;        but this is not a sitation you'll find often\r
35 ;\r
36 ;  B) Alternative\r
37 ;    if you are not interresed in old cpu performance and want the smaller\r
38 ;       binaries possible\r
39 ;\r
40 ;    compile the asm file running\r
41 ;           ml /coff /Zi /c /Flgvmat32.lst /DNOOLDPENTIUMCODE gvmat32.asm\r
42 ;    and do not include gvmat32c.c in your project (ou define also \r
43 ;              NOOLDPENTIUMCODE)\r
44 ;\r
45 ; note : as I known, longest_match_686 is very faster than longest_match_7fff\r
46 ;        on pentium Pro/II/III, faster (but less) in P4, but it seem\r
47 ;        longest_match_7fff can be faster (very very litte) on AMD Athlon64/K8\r
48 ;\r
49 ; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2\r
50 \r
51 ;uInt longest_match_7fff(s, cur_match)\r
52 ;    deflate_state *s;\r
53 ;    IPos cur_match;                             /* current match */\r
54 \r
55     NbStack         equ     76\r
56     cur_match       equ     dword ptr[esp+NbStack-0]\r
57     str_s           equ     dword ptr[esp+NbStack-4]\r
58 ; 5 dword on top (ret,ebp,esi,edi,ebx)\r
59     adrret          equ     dword ptr[esp+NbStack-8]\r
60     pushebp         equ     dword ptr[esp+NbStack-12]\r
61     pushedi         equ     dword ptr[esp+NbStack-16]\r
62     pushesi         equ     dword ptr[esp+NbStack-20]\r
63     pushebx         equ     dword ptr[esp+NbStack-24]\r
64 \r
65     chain_length    equ     dword ptr [esp+NbStack-28]\r
66     limit           equ     dword ptr [esp+NbStack-32]\r
67     best_len        equ     dword ptr [esp+NbStack-36]\r
68     window          equ     dword ptr [esp+NbStack-40]\r
69     prev            equ     dword ptr [esp+NbStack-44]\r
70     scan_start      equ      word ptr [esp+NbStack-48]\r
71     wmask           equ     dword ptr [esp+NbStack-52]\r
72     match_start_ptr equ     dword ptr [esp+NbStack-56]\r
73     nice_match      equ     dword ptr [esp+NbStack-60]\r
74     scan            equ     dword ptr [esp+NbStack-64]\r
75 \r
76     windowlen       equ     dword ptr [esp+NbStack-68]\r
77     match_start     equ     dword ptr [esp+NbStack-72]\r
78     strend          equ     dword ptr [esp+NbStack-76]\r
79     NbStackAdd      equ     (NbStack-24)\r
80 \r
81     .386p\r
82 \r
83     name    gvmatch\r
84     .MODEL  FLAT\r
85 \r
86 \r
87 \r
88 ;  all the +zlib1222add offsets are due to the addition of fields\r
89 ;  in zlib in the deflate_state structure since the asm code was first written\r
90 ;  (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").\r
91 ;  (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").\r
92 ;  if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").\r
93 \r
94     zlib1222add         equ     8\r
95 \r
96 ;  Note : these value are good with a 8 bytes boundary pack structure\r
97     dep_chain_length    equ     74h+zlib1222add\r
98     dep_window          equ     30h+zlib1222add\r
99     dep_strstart        equ     64h+zlib1222add\r
100     dep_prev_length     equ     70h+zlib1222add\r
101     dep_nice_match      equ     88h+zlib1222add\r
102     dep_w_size          equ     24h+zlib1222add\r
103     dep_prev            equ     38h+zlib1222add\r
104     dep_w_mask          equ     2ch+zlib1222add\r
105     dep_good_match      equ     84h+zlib1222add\r
106     dep_match_start     equ     68h+zlib1222add\r
107     dep_lookahead       equ     6ch+zlib1222add\r
108 \r
109 \r
110 _TEXT                   segment\r
111 \r
112 IFDEF NOUNDERLINE\r
113    IFDEF NOOLDPENTIUMCODE\r
114             public  longest_match\r
115             public  match_init\r
116    ELSE            \r
117             public  longest_match_7fff\r
118             public  cpudetect32\r
119             public  longest_match_686\r
120    ENDIF\r
121 ELSE\r
122    IFDEF NOOLDPENTIUMCODE\r
123             public  _longest_match\r
124             public  _match_init\r
125    ELSE\r
126             public  _longest_match_7fff\r
127             public  _cpudetect32\r
128             public  _longest_match_686\r
129    ENDIF\r
130 ENDIF\r
131 \r
132     MAX_MATCH           equ     258\r
133     MIN_MATCH           equ     3\r
134     MIN_LOOKAHEAD       equ     (MAX_MATCH+MIN_MATCH+1)\r
135 \r
136 \r
137 \r
138 IFNDEF NOOLDPENTIUMCODE\r
139 IFDEF NOUNDERLINE\r
140 longest_match_7fff   proc near\r
141 ELSE\r
142 _longest_match_7fff  proc near\r
143 ENDIF\r
144 \r
145     mov     edx,[esp+4]\r
146 \r
147 \r
148 \r
149     push    ebp\r
150     push    edi\r
151     push    esi\r
152     push    ebx\r
153 \r
154     sub     esp,NbStackAdd\r
155 \r
156 ; initialize or check the variables used in match.asm.\r
157     mov     ebp,edx\r
158 \r
159 ; chain_length = s->max_chain_length\r
160 ; if (prev_length>=good_match) chain_length >>= 2\r
161     mov     edx,[ebp+dep_chain_length]\r
162     mov     ebx,[ebp+dep_prev_length]\r
163     cmp     [ebp+dep_good_match],ebx\r
164     ja      noshr\r
165     shr     edx,2\r
166 noshr:\r
167 ; we increment chain_length because in the asm, the --chain_lenght is in the beginning of the loop\r
168     inc     edx\r
169     mov     edi,[ebp+dep_nice_match]\r
170     mov     chain_length,edx\r
171     mov     eax,[ebp+dep_lookahead]\r
172     cmp     eax,edi\r
173 ; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;\r
174     jae     nolookaheadnicematch\r
175     mov     edi,eax\r
176 nolookaheadnicematch:\r
177 ; best_len = s->prev_length\r
178     mov     best_len,ebx\r
179 \r
180 ; window = s->window\r
181     mov     esi,[ebp+dep_window]\r
182     mov     ecx,[ebp+dep_strstart]\r
183     mov     window,esi\r
184 \r
185     mov     nice_match,edi\r
186 ; scan = window + strstart\r
187     add     esi,ecx\r
188     mov     scan,esi\r
189 ; dx = *window\r
190     mov     dx,word ptr [esi]\r
191 ; bx = *(window+best_len-1)\r
192     mov     bx,word ptr [esi+ebx-1]\r
193     add     esi,MAX_MATCH-1\r
194 ; scan_start = *scan\r
195     mov     scan_start,dx\r
196 ; strend = scan + MAX_MATCH-1\r
197     mov     strend,esi\r
198 ; bx = scan_end = *(window+best_len-1)\r
199 \r
200 ;    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?\r
201 ;        s->strstart - (IPos)MAX_DIST(s) : NIL;\r
202 \r
203     mov     esi,[ebp+dep_w_size]\r
204     sub     esi,MIN_LOOKAHEAD\r
205 ; here esi = MAX_DIST(s)\r
206     sub     ecx,esi\r
207     ja      nodist\r
208     xor     ecx,ecx\r
209 nodist:\r
210     mov     limit,ecx\r
211 \r
212 ; prev = s->prev\r
213     mov     edx,[ebp+dep_prev]\r
214     mov     prev,edx\r
215 \r
216 ;\r
217     mov     edx,dword ptr [ebp+dep_match_start]\r
218     mov     bp,scan_start\r
219     mov     eax,cur_match\r
220     mov     match_start,edx\r
221 \r
222     mov     edx,window\r
223     mov     edi,edx\r
224     add     edi,best_len\r
225     mov     esi,prev\r
226     dec     edi\r
227 ; windowlen = window + best_len -1\r
228     mov     windowlen,edi\r
229 \r
230     jmp     beginloop2\r
231     align   4\r
232 \r
233 ; here, in the loop\r
234 ;       eax = ax = cur_match\r
235 ;       ecx = limit\r
236 ;        bx = scan_end\r
237 ;        bp = scan_start\r
238 ;       edi = windowlen (window + best_len -1)\r
239 ;       esi = prev\r
240 \r
241 \r
242 ;// here; chain_length <=16\r
243 normalbeg0add16:\r
244     add     chain_length,16\r
245     jz      exitloop\r
246 normalbeg0:\r
247     cmp     word ptr[edi+eax],bx\r
248     je      normalbeg2noroll\r
249 rcontlabnoroll:\r
250 ; cur_match = prev[cur_match & wmask]\r
251     and     eax,7fffh\r
252     mov     ax,word ptr[esi+eax*2]\r
253 ; if cur_match > limit, go to exitloop\r
254     cmp     ecx,eax\r
255     jnb     exitloop\r
256 ; if --chain_length != 0, go to exitloop\r
257     dec     chain_length\r
258     jnz     normalbeg0\r
259     jmp     exitloop\r
260 \r
261 normalbeg2noroll:\r
262 ; if (scan_start==*(cur_match+window)) goto normalbeg2\r
263     cmp     bp,word ptr[edx+eax]\r
264     jne     rcontlabnoroll\r
265     jmp     normalbeg2\r
266 \r
267 contloop3:\r
268     mov     edi,windowlen\r
269 \r
270 ; cur_match = prev[cur_match & wmask]\r
271     and     eax,7fffh\r
272     mov     ax,word ptr[esi+eax*2]\r
273 ; if cur_match > limit, go to exitloop\r
274     cmp     ecx,eax\r
275 jnbexitloopshort1:\r
276     jnb     exitloop\r
277 ; if --chain_length != 0, go to exitloop\r
278 \r
279 \r
280 ; begin the main loop\r
281 beginloop2:\r
282     sub     chain_length,16+1\r
283 ; if chain_length <=16, don't use the unrolled loop\r
284     jna     normalbeg0add16\r
285 \r
286 do16:\r
287     cmp     word ptr[edi+eax],bx\r
288     je      normalbeg2dc0\r
289 \r
290 maccn   MACRO   lab\r
291     and     eax,7fffh\r
292     mov     ax,word ptr[esi+eax*2]\r
293     cmp     ecx,eax\r
294     jnb     exitloop\r
295     cmp     word ptr[edi+eax],bx\r
296     je      lab\r
297     ENDM\r
298 \r
299 rcontloop0:\r
300     maccn   normalbeg2dc1\r
301 \r
302 rcontloop1:\r
303     maccn   normalbeg2dc2\r
304 \r
305 rcontloop2:\r
306     maccn   normalbeg2dc3\r
307 \r
308 rcontloop3:\r
309     maccn   normalbeg2dc4\r
310 \r
311 rcontloop4:\r
312     maccn   normalbeg2dc5\r
313 \r
314 rcontloop5:\r
315     maccn   normalbeg2dc6\r
316 \r
317 rcontloop6:\r
318     maccn   normalbeg2dc7\r
319 \r
320 rcontloop7:\r
321     maccn   normalbeg2dc8\r
322 \r
323 rcontloop8:\r
324     maccn   normalbeg2dc9\r
325 \r
326 rcontloop9:\r
327     maccn   normalbeg2dc10\r
328 \r
329 rcontloop10:\r
330     maccn   short normalbeg2dc11\r
331 \r
332 rcontloop11:\r
333     maccn   short normalbeg2dc12\r
334 \r
335 rcontloop12:\r
336     maccn   short normalbeg2dc13\r
337 \r
338 rcontloop13:\r
339     maccn   short normalbeg2dc14\r
340 \r
341 rcontloop14:\r
342     maccn   short normalbeg2dc15\r
343 \r
344 rcontloop15:\r
345     and     eax,7fffh\r
346     mov     ax,word ptr[esi+eax*2]\r
347     cmp     ecx,eax\r
348     jnb     exitloop\r
349 \r
350     sub     chain_length,16\r
351     ja      do16\r
352     jmp     normalbeg0add16\r
353 \r
354 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
355 \r
356 normbeg MACRO   rcontlab,valsub\r
357 ; if we are here, we know that *(match+best_len-1) == scan_end\r
358     cmp     bp,word ptr[edx+eax]\r
359 ; if (match != scan_start) goto rcontlab\r
360     jne     rcontlab\r
361 ; calculate the good chain_length, and we'll compare scan and match string\r
362     add     chain_length,16-valsub\r
363     jmp     iseq\r
364     ENDM\r
365 \r
366 \r
367 normalbeg2dc11:\r
368     normbeg rcontloop11,11\r
369 \r
370 normalbeg2dc12:\r
371     normbeg short rcontloop12,12\r
372 \r
373 normalbeg2dc13:\r
374     normbeg short rcontloop13,13\r
375 \r
376 normalbeg2dc14:\r
377     normbeg short rcontloop14,14\r
378 \r
379 normalbeg2dc15:\r
380     normbeg short rcontloop15,15\r
381 \r
382 normalbeg2dc10:\r
383     normbeg rcontloop10,10\r
384 \r
385 normalbeg2dc9:\r
386     normbeg rcontloop9,9\r
387 \r
388 normalbeg2dc8:\r
389     normbeg rcontloop8,8\r
390 \r
391 normalbeg2dc7:\r
392     normbeg rcontloop7,7\r
393 \r
394 normalbeg2dc6:\r
395     normbeg rcontloop6,6\r
396 \r
397 normalbeg2dc5:\r
398     normbeg rcontloop5,5\r
399 \r
400 normalbeg2dc4:\r
401     normbeg rcontloop4,4\r
402 \r
403 normalbeg2dc3:\r
404     normbeg rcontloop3,3\r
405 \r
406 normalbeg2dc2:\r
407     normbeg rcontloop2,2\r
408 \r
409 normalbeg2dc1:\r
410     normbeg rcontloop1,1\r
411 \r
412 normalbeg2dc0:\r
413     normbeg rcontloop0,0\r
414 \r
415 \r
416 ; we go in normalbeg2 because *(ushf*)(match+best_len-1) == scan_end\r
417 \r
418 normalbeg2:\r
419     mov     edi,window\r
420 \r
421     cmp     bp,word ptr[edi+eax]\r
422     jne     contloop3                   ; if *(ushf*)match != scan_start, continue\r
423 \r
424 iseq:\r
425 ; if we are here, we know that *(match+best_len-1) == scan_end\r
426 ; and (match == scan_start)\r
427 \r
428     mov     edi,edx\r
429     mov     esi,scan                    ; esi = scan\r
430     add     edi,eax                     ; edi = window + cur_match = match\r
431 \r
432     mov     edx,[esi+3]                 ; compare manually dword at match+3\r
433     xor     edx,[edi+3]                 ; and scan +3\r
434 \r
435     jz      begincompare                ; if equal, go to long compare\r
436 \r
437 ; we will determine the unmatch byte and calculate len (in esi)\r
438     or      dl,dl\r
439     je      eq1rr\r
440     mov     esi,3\r
441     jmp     trfinval\r
442 eq1rr:\r
443     or      dx,dx\r
444     je      eq1\r
445 \r
446     mov     esi,4\r
447     jmp     trfinval\r
448 eq1:\r
449     and     edx,0ffffffh\r
450     jz      eq11\r
451     mov     esi,5\r
452     jmp     trfinval\r
453 eq11:\r
454     mov     esi,6\r
455     jmp     trfinval\r
456 \r
457 begincompare:\r
458     ; here we now scan and match begin same\r
459     add     edi,6\r
460     add     esi,6\r
461     mov     ecx,(MAX_MATCH-(2+4))/4     ; scan for at most MAX_MATCH bytes\r
462     repe    cmpsd                       ; loop until mismatch\r
463 \r
464     je      trfin                       ; go to trfin if not unmatch\r
465 ; we determine the unmatch byte\r
466     sub     esi,4\r
467     mov     edx,[edi-4]\r
468     xor     edx,[esi]\r
469 \r
470     or      dl,dl\r
471     jnz     trfin\r
472     inc     esi\r
473 \r
474     or      dx,dx\r
475     jnz     trfin\r
476     inc     esi\r
477 \r
478     and     edx,0ffffffh\r
479     jnz     trfin\r
480     inc     esi\r
481 \r
482 trfin:\r
483     sub     esi,scan          ; esi = len\r
484 trfinval:\r
485 ; here we have finised compare, and esi contain len of equal string\r
486     cmp     esi,best_len        ; if len > best_len, go newbestlen\r
487     ja      short newbestlen\r
488 ; now we restore edx, ecx and esi, for the big loop\r
489     mov     esi,prev\r
490     mov     ecx,limit\r
491     mov     edx,window\r
492     jmp     contloop3\r
493 \r
494 newbestlen:\r
495     mov     best_len,esi        ; len become best_len\r
496 \r
497     mov     match_start,eax     ; save new position as match_start\r
498     cmp     esi,nice_match      ; if best_len >= nice_match, exit\r
499     jae     exitloop\r
500     mov     ecx,scan\r
501     mov     edx,window          ; restore edx=window\r
502     add     ecx,esi\r
503     add     esi,edx\r
504 \r
505     dec     esi\r
506     mov     windowlen,esi       ; windowlen = window + best_len-1\r
507     mov     bx,[ecx-1]          ; bx = *(scan+best_len-1) = scan_end\r
508 \r
509 ; now we restore ecx and esi, for the big loop :\r
510     mov     esi,prev\r
511     mov     ecx,limit\r
512     jmp     contloop3\r
513 \r
514 exitloop:\r
515 ; exit : s->match_start=match_start\r
516     mov     ebx,match_start\r
517     mov     ebp,str_s\r
518     mov     ecx,best_len\r
519     mov     dword ptr [ebp+dep_match_start],ebx\r
520     mov     eax,dword ptr [ebp+dep_lookahead]\r
521     cmp     ecx,eax\r
522     ja      minexlo\r
523     mov     eax,ecx\r
524 minexlo:\r
525 ; return min(best_len,s->lookahead)\r
526 \r
527 ; restore stack and register ebx,esi,edi,ebp\r
528     add     esp,NbStackAdd\r
529 \r
530     pop     ebx\r
531     pop     esi\r
532     pop     edi\r
533     pop     ebp\r
534     ret\r
535 InfoAuthor:\r
536 ; please don't remove this string !\r
537 ; Your are free use gvmat32 in any fre or commercial apps if you don't remove the string in the binary!\r
538     db     0dh,0ah,"GVMat32 optimised assembly code written 1996-98 by Gilles Vollant",0dh,0ah\r
539 \r
540 \r
541 \r
542 IFDEF NOUNDERLINE\r
543 longest_match_7fff   endp\r
544 ELSE\r
545 _longest_match_7fff  endp\r
546 ENDIF\r
547 \r
548 \r
549 IFDEF NOUNDERLINE\r
550 cpudetect32     proc near\r
551 ELSE\r
552 _cpudetect32    proc near\r
553 ENDIF\r
554 \r
555     push    ebx\r
556 \r
557     pushfd                  ; push original EFLAGS\r
558     pop     eax             ; get original EFLAGS\r
559     mov     ecx, eax        ; save original EFLAGS\r
560     xor     eax, 40000h     ; flip AC bit in EFLAGS\r
561     push    eax             ; save new EFLAGS value on stack\r
562     popfd                   ; replace current EFLAGS value\r
563     pushfd                  ; get new EFLAGS\r
564     pop     eax             ; store new EFLAGS in EAX\r
565     xor     eax, ecx        ; can\92t toggle AC bit, processor=80386\r
566     jz      end_cpu_is_386  ; jump if 80386 processor\r
567     push    ecx\r
568     popfd                   ; restore AC bit in EFLAGS first\r
569 \r
570     pushfd\r
571     pushfd\r
572     pop     ecx\r
573 \r
574     mov     eax, ecx        ; get original EFLAGS\r
575     xor     eax, 200000h    ; flip ID bit in EFLAGS\r
576     push    eax             ; save new EFLAGS value on stack\r
577     popfd                   ; replace current EFLAGS value\r
578     pushfd                  ; get new EFLAGS\r
579     pop     eax             ; store new EFLAGS in EAX\r
580     popfd                   ; restore original EFLAGS\r
581     xor     eax, ecx        ; can\92t toggle ID bit,\r
582     je      is_old_486      ; processor=old\r
583 \r
584     mov     eax,1\r
585     db      0fh,0a2h        ;CPUID\r
586 \r
587 exitcpudetect:\r
588     pop ebx\r
589     ret\r
590 \r
591 end_cpu_is_386:\r
592     mov     eax,0300h\r
593     jmp     exitcpudetect\r
594 \r
595 is_old_486:\r
596     mov     eax,0400h\r
597     jmp     exitcpudetect\r
598 \r
599 IFDEF NOUNDERLINE\r
600 cpudetect32     endp\r
601 ELSE\r
602 _cpudetect32    endp\r
603 ENDIF\r
604 ENDIF\r
605 \r
606 MAX_MATCH       equ     258\r
607 MIN_MATCH       equ     3\r
608 MIN_LOOKAHEAD   equ     (MAX_MATCH + MIN_MATCH + 1)\r
609 MAX_MATCH_8_     equ     ((MAX_MATCH + 7) AND 0FFF0h)\r
610 \r
611 \r
612 ;;; stack frame offsets\r
613 \r
614 chainlenwmask   equ  esp + 0    ; high word: current chain len\r
615                     ; low word: s->wmask\r
616 window      equ  esp + 4    ; local copy of s->window\r
617 windowbestlen   equ  esp + 8    ; s->window + bestlen\r
618 scanstart   equ  esp + 16   ; first two bytes of string\r
619 scanend     equ  esp + 12   ; last two bytes of string\r
620 scanalign   equ  esp + 20   ; dword-misalignment of string\r
621 nicematch   equ  esp + 24   ; a good enough match size\r
622 bestlen     equ  esp + 28   ; size of best match so far\r
623 scan        equ  esp + 32   ; ptr to string wanting match\r
624 \r
625 LocalVarsSize   equ 36\r
626 ;   saved ebx   byte esp + 36\r
627 ;   saved edi   byte esp + 40\r
628 ;   saved esi   byte esp + 44\r
629 ;   saved ebp   byte esp + 48\r
630 ;   return address  byte esp + 52\r
631 deflatestate    equ  esp + 56   ; the function arguments\r
632 curmatch    equ  esp + 60\r
633 \r
634 ;;; Offsets for fields in the deflate_state structure. These numbers\r
635 ;;; are calculated from the definition of deflate_state, with the\r
636 ;;; assumption that the compiler will dword-align the fields. (Thus,\r
637 ;;; changing the definition of deflate_state could easily cause this\r
638 ;;; program to crash horribly, without so much as a warning at\r
639 ;;; compile time. Sigh.)\r
640 \r
641 dsWSize     equ 36+zlib1222add\r
642 dsWMask     equ 44+zlib1222add\r
643 dsWindow    equ 48+zlib1222add\r
644 dsPrev      equ 56+zlib1222add\r
645 dsMatchLen  equ 88+zlib1222add\r
646 dsPrevMatch equ 92+zlib1222add\r
647 dsStrStart  equ 100+zlib1222add\r
648 dsMatchStart    equ 104+zlib1222add\r
649 dsLookahead equ 108+zlib1222add\r
650 dsPrevLen   equ 112+zlib1222add\r
651 dsMaxChainLen   equ 116+zlib1222add\r
652 dsGoodMatch equ 132+zlib1222add\r
653 dsNiceMatch equ 136+zlib1222add\r
654 \r
655 \r
656 ;;; match.asm -- Pentium-Pro-optimized version of longest_match()\r
657 ;;; Written for zlib 1.1.2\r
658 ;;; Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>\r
659 ;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html\r
660 ;;;\r
661 ;;; This is free software; you can redistribute it and/or modify it\r
662 ;;; under the terms of the GNU General Public License.\r
663 \r
664 ;GLOBAL _longest_match, _match_init\r
665 \r
666 \r
667 ;SECTION    .text\r
668 \r
669 ;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch)\r
670 \r
671 ;_longest_match:\r
672 IFDEF NOOLDPENTIUMCODE\r
673     IFDEF NOUNDERLINE\r
674     longest_match       proc near\r
675     ELSE\r
676     _longest_match      proc near\r
677     ENDIF\r
678 ELSE\r
679     IFDEF NOUNDERLINE\r
680     longest_match_686   proc near\r
681     ELSE\r
682     _longest_match_686  proc near\r
683     ENDIF\r
684 ENDIF\r
685 \r
686 ;;; Save registers that the compiler may be using, and adjust esp to\r
687 ;;; make room for our stack frame.\r
688 \r
689         push    ebp\r
690         push    edi\r
691         push    esi\r
692         push    ebx\r
693         sub esp, LocalVarsSize\r
694 \r
695 ;;; Retrieve the function arguments. ecx will hold cur_match\r
696 ;;; throughout the entire function. edx will hold the pointer to the\r
697 ;;; deflate_state structure during the function's setup (before\r
698 ;;; entering the main loop.\r
699 \r
700         mov edx, [deflatestate]\r
701         mov ecx, [curmatch]\r
702 \r
703 ;;; uInt wmask = s->w_mask;\r
704 ;;; unsigned chain_length = s->max_chain_length;\r
705 ;;; if (s->prev_length >= s->good_match) {\r
706 ;;;     chain_length >>= 2;\r
707 ;;; }\r
708 \r
709         mov eax, [edx + dsPrevLen]\r
710         mov ebx, [edx + dsGoodMatch]\r
711         cmp eax, ebx\r
712         mov eax, [edx + dsWMask]\r
713         mov ebx, [edx + dsMaxChainLen]\r
714         jl  LastMatchGood\r
715         shr ebx, 2\r
716 LastMatchGood:\r
717 \r
718 ;;; chainlen is decremented once beforehand so that the function can\r
719 ;;; use the sign flag instead of the zero flag for the exit test.\r
720 ;;; It is then shifted into the high word, to make room for the wmask\r
721 ;;; value, which it will always accompany.\r
722 \r
723         dec ebx\r
724         shl ebx, 16\r
725         or  ebx, eax\r
726         mov [chainlenwmask], ebx\r
727 \r
728 ;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;\r
729 \r
730         mov eax, [edx + dsNiceMatch]\r
731         mov ebx, [edx + dsLookahead]\r
732         cmp ebx, eax\r
733         jl  LookaheadLess\r
734         mov ebx, eax\r
735 LookaheadLess:  mov [nicematch], ebx\r
736 \r
737 ;;; register Bytef *scan = s->window + s->strstart;\r
738 \r
739         mov esi, [edx + dsWindow]\r
740         mov [window], esi\r
741         mov ebp, [edx + dsStrStart]\r
742         lea edi, [esi + ebp]\r
743         mov [scan], edi\r
744 \r
745 ;;; Determine how many bytes the scan ptr is off from being\r
746 ;;; dword-aligned.\r
747 \r
748         mov eax, edi\r
749         neg eax\r
750         and eax, 3\r
751         mov [scanalign], eax\r
752 \r
753 ;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?\r
754 ;;;     s->strstart - (IPos)MAX_DIST(s) : NIL;\r
755 \r
756         mov eax, [edx + dsWSize]\r
757         sub eax, MIN_LOOKAHEAD\r
758         sub ebp, eax\r
759         jg  LimitPositive\r
760         xor ebp, ebp\r
761 LimitPositive:\r
762 \r
763 ;;; int best_len = s->prev_length;\r
764 \r
765         mov eax, [edx + dsPrevLen]\r
766         mov [bestlen], eax\r
767 \r
768 ;;; Store the sum of s->window + best_len in esi locally, and in esi.\r
769 \r
770         add esi, eax\r
771         mov [windowbestlen], esi\r
772 \r
773 ;;; register ush scan_start = *(ushf*)scan;\r
774 ;;; register ush scan_end   = *(ushf*)(scan+best_len-1);\r
775 ;;; Posf *prev = s->prev;\r
776 \r
777         movzx   ebx, word ptr [edi]\r
778         mov [scanstart], ebx\r
779         movzx   ebx, word ptr [edi + eax - 1]\r
780         mov [scanend], ebx\r
781         mov edi, [edx + dsPrev]\r
782 \r
783 ;;; Jump into the main loop.\r
784 \r
785         mov edx, [chainlenwmask]\r
786         jmp short LoopEntry\r
787 \r
788 align 4\r
789 \r
790 ;;; do {\r
791 ;;;     match = s->window + cur_match;\r
792 ;;;     if (*(ushf*)(match+best_len-1) != scan_end ||\r
793 ;;;         *(ushf*)match != scan_start) continue;\r
794 ;;;     [...]\r
795 ;;; } while ((cur_match = prev[cur_match & wmask]) > limit\r
796 ;;;          && --chain_length != 0);\r
797 ;;;\r
798 ;;; Here is the inner loop of the function. The function will spend the\r
799 ;;; majority of its time in this loop, and majority of that time will\r
800 ;;; be spent in the first ten instructions.\r
801 ;;;\r
802 ;;; Within this loop:\r
803 ;;; ebx = scanend\r
804 ;;; ecx = curmatch\r
805 ;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)\r
806 ;;; esi = windowbestlen - i.e., (window + bestlen)\r
807 ;;; edi = prev\r
808 ;;; ebp = limit\r
809 \r
810 LookupLoop:\r
811         and ecx, edx\r
812         movzx   ecx, word ptr [edi + ecx*2]\r
813         cmp ecx, ebp\r
814         jbe LeaveNow\r
815         sub edx, 00010000h\r
816         js  LeaveNow\r
817 LoopEntry:  movzx   eax, word ptr [esi + ecx - 1]\r
818         cmp eax, ebx\r
819         jnz LookupLoop\r
820         mov eax, [window]\r
821         movzx   eax, word ptr [eax + ecx]\r
822         cmp eax, [scanstart]\r
823         jnz LookupLoop\r
824 \r
825 ;;; Store the current value of chainlen.\r
826 \r
827         mov [chainlenwmask], edx\r
828 \r
829 ;;; Point edi to the string under scrutiny, and esi to the string we\r
830 ;;; are hoping to match it up with. In actuality, esi and edi are\r
831 ;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is\r
832 ;;; initialized to -(MAX_MATCH_8 - scanalign).\r
833 \r
834         mov esi, [window]\r
835         mov edi, [scan]\r
836         add esi, ecx\r
837         mov eax, [scanalign]\r
838         mov edx, 0fffffef8h; -(MAX_MATCH_8)\r
839         lea edi, [edi + eax + 0108h] ;MAX_MATCH_8]\r
840         lea esi, [esi + eax + 0108h] ;MAX_MATCH_8]\r
841 \r
842 ;;; Test the strings for equality, 8 bytes at a time. At the end,\r
843 ;;; adjust edx so that it is offset to the exact byte that mismatched.\r
844 ;;;\r
845 ;;; We already know at this point that the first three bytes of the\r
846 ;;; strings match each other, and they can be safely passed over before\r
847 ;;; starting the compare loop. So what this code does is skip over 0-3\r
848 ;;; bytes, as much as necessary in order to dword-align the edi\r
849 ;;; pointer. (esi will still be misaligned three times out of four.)\r
850 ;;;\r
851 ;;; It should be confessed that this loop usually does not represent\r
852 ;;; much of the total running time. Replacing it with a more\r
853 ;;; straightforward "rep cmpsb" would not drastically degrade\r
854 ;;; performance.\r
855 \r
856 LoopCmps:\r
857         mov eax, [esi + edx]\r
858         xor eax, [edi + edx]\r
859         jnz LeaveLoopCmps\r
860         mov eax, [esi + edx + 4]\r
861         xor eax, [edi + edx + 4]\r
862         jnz LeaveLoopCmps4\r
863         add edx, 8\r
864         jnz LoopCmps\r
865         jmp short LenMaximum\r
866 LeaveLoopCmps4: add edx, 4\r
867 LeaveLoopCmps:  test    eax, 0000FFFFh\r
868         jnz LenLower\r
869         add edx,  2\r
870         shr eax, 16\r
871 LenLower:   sub al, 1\r
872         adc edx, 0\r
873 \r
874 ;;; Calculate the length of the match. If it is longer than MAX_MATCH,\r
875 ;;; then automatically accept it as the best possible match and leave.\r
876 \r
877         lea eax, [edi + edx]\r
878         mov edi, [scan]\r
879         sub eax, edi\r
880         cmp eax, MAX_MATCH\r
881         jge LenMaximum\r
882 \r
883 ;;; If the length of the match is not longer than the best match we\r
884 ;;; have so far, then forget it and return to the lookup loop.\r
885 \r
886         mov edx, [deflatestate]\r
887         mov ebx, [bestlen]\r
888         cmp eax, ebx\r
889         jg  LongerMatch\r
890         mov esi, [windowbestlen]\r
891         mov edi, [edx + dsPrev]\r
892         mov ebx, [scanend]\r
893         mov edx, [chainlenwmask]\r
894         jmp LookupLoop\r
895 \r
896 ;;;         s->match_start = cur_match;\r
897 ;;;         best_len = len;\r
898 ;;;         if (len >= nice_match) break;\r
899 ;;;         scan_end = *(ushf*)(scan+best_len-1);\r
900 \r
901 LongerMatch:    mov ebx, [nicematch]\r
902         mov [bestlen], eax\r
903         mov [edx + dsMatchStart], ecx\r
904         cmp eax, ebx\r
905         jge LeaveNow\r
906         mov esi, [window]\r
907         add esi, eax\r
908         mov [windowbestlen], esi\r
909         movzx   ebx, word ptr [edi + eax - 1]\r
910         mov edi, [edx + dsPrev]\r
911         mov [scanend], ebx\r
912         mov edx, [chainlenwmask]\r
913         jmp LookupLoop\r
914 \r
915 ;;; Accept the current string, with the maximum possible length.\r
916 \r
917 LenMaximum: mov edx, [deflatestate]\r
918         mov dword ptr [bestlen], MAX_MATCH\r
919         mov [edx + dsMatchStart], ecx\r
920 \r
921 ;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;\r
922 ;;; return s->lookahead;\r
923 \r
924 LeaveNow:\r
925         mov edx, [deflatestate]\r
926         mov ebx, [bestlen]\r
927         mov eax, [edx + dsLookahead]\r
928         cmp ebx, eax\r
929         jg  LookaheadRet\r
930         mov eax, ebx\r
931 LookaheadRet:\r
932 \r
933 ;;; Restore the stack and return from whence we came.\r
934 \r
935         add esp, LocalVarsSize\r
936         pop ebx\r
937         pop esi\r
938         pop edi\r
939         pop ebp\r
940 \r
941         ret\r
942 ; please don't remove this string !\r
943 ; Your can freely use gvmat32 in any free or commercial app if you don't remove the string in the binary!\r
944     db     0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah\r
945 \r
946 \r
947 IFDEF NOOLDPENTIUMCODE\r
948     IFDEF NOUNDERLINE\r
949     longest_match       endp\r
950     ELSE\r
951     _longest_match      endp\r
952     ENDIF\r
953 \r
954     IFDEF NOUNDERLINE\r
955     match_init      proc near\r
956                     ret\r
957     match_init      endp\r
958     ELSE\r
959     _match_init     proc near\r
960                     ret\r
961     _match_init     endp\r
962     ENDIF    \r
963 ELSE\r
964     IFDEF NOUNDERLINE\r
965     longest_match_686   endp\r
966     ELSE\r
967     _longest_match_686  endp\r
968     ENDIF\r
969 ENDIF\r
970 \r
971 _TEXT   ends\r
972 end\r