1 ; match686.asm -- Asm portion of the optimized longest_match for 32 bits x86
2 ; Copyright (C) 1995-1996 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
3 ; File written by Gilles Vollant, by converting match686.S from Brian Raiter
4 ; for MASM. This is as assembly version of longest_match
5 ; from Jean-loup Gailly in deflate.c
8 ; http://www.winimage.com/zLibDll
9 ; http://www.muppetlabs.com/~breadbox/software/assembly.html
11 ; For Visual C++ 4.x and higher and ML 6.x and higher
12 ; ml.exe is distributed in
13 ; http://www.microsoft.com/downloads/details.aspx?FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64
15 ; this file contain two implementation of longest_match
17 ; this longest_match was written by Brian raiter (1998), optimized for Pentium Pro
18 ; (and the faster known version of match_init on modern Core 2 Duo and AMD Phenom)
20 ; for using an assembly version of longest_match, you need define ASMV in project
22 ; compile the asm file running
23 ; ml /coff /Zi /c /Flmatch686.lst match686.asm
24 ; and do not include match686.obj in your project
26 ; note: contrib of zLib 1.2.3 and earlier contained both a deprecated version for
27 ; Pentium (prior Pentium Pro) and this version for Pentium Pro and modern processor
28 ; with autoselect (with cpu detection code)
29 ; if you want support the old pentium optimization, you can still use these version
31 ; this file is not optimized for old pentium, but it compatible with all x86 32 bits
32 ; processor (starting 80386)
35 ; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2
37 ;uInt longest_match(s, cur_match)
39 ; IPos cur_match; /* current match */
42 cur_match
equ dword ptr[esp+NbStack
-0]
43 str_s
equ dword ptr[esp+NbStack
-4]
44 ; 5 dword on top (ret,ebp,esi,edi,ebx)
45 adrret
equ dword ptr[esp+NbStack
-8]
46 pushebp
equ dword ptr[esp+NbStack
-12]
47 pushedi
equ dword ptr[esp+NbStack
-16]
48 pushesi
equ dword ptr[esp+NbStack
-20]
49 pushebx
equ dword ptr[esp+NbStack
-24]
51 chain_length
equ dword ptr [esp+NbStack
-28]
52 limit
equ dword ptr [esp+NbStack
-32]
53 best_len
equ dword ptr [esp+NbStack
-36]
54 window
equ dword ptr [esp+NbStack
-40]
55 prev
equ dword ptr [esp+NbStack
-44]
56 scan_start
equ word ptr [esp+NbStack
-48]
57 wmask
equ dword ptr [esp+NbStack
-52]
58 match_start_ptr
equ dword ptr [esp+NbStack
-56]
59 nice_match
equ dword ptr [esp+NbStack
-60]
60 scan
equ dword ptr [esp+NbStack
-64]
62 windowlen
equ dword ptr [esp+NbStack
-68]
63 match_start
equ dword ptr [esp+NbStack
-72]
64 strend
equ dword ptr [esp+NbStack
-76]
65 NbStackAdd
equ (NbStack
-24)
74 ; all the +zlib1222add offsets are due to the addition of fields
75 ; in zlib in the deflate_state structure since the asm code was first written
76 ; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
77 ; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
78 ; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
82 ; Note : these value are good with a 8 bytes boundary pack structure
83 dep_chain_length
equ 74h+zlib1222add
84 dep_window
equ 30h+zlib1222add
85 dep_strstart
equ 64h+zlib1222add
86 dep_prev_length
equ 70h+zlib1222add
87 dep_nice_match
equ 88h+zlib1222add
88 dep_w_size
equ 24h+zlib1222add
89 dep_prev
equ 38h+zlib1222add
90 dep_w_mask
equ 2ch+zlib1222add
91 dep_good_match
equ 84h+zlib1222add
92 dep_match_start
equ 68h+zlib1222add
93 dep_lookahead
equ 6ch+zlib1222add
102 public _longest_match
108 MIN_LOOKAHEAD
equ (MAX_MATCH
+MIN_MATCH
+1)
114 MIN_LOOKAHEAD
equ (MAX_MATCH
+ MIN_MATCH
+ 1)
115 MAX_MATCH_8_
equ ((MAX_MATCH
+ 7) AND 0FFF0h
)
118 ;;; stack frame offsets
120 chainlenwmask
equ esp + 0 ; high word: current chain len
122 window
equ esp + 4 ; local copy of s->window
123 windowbestlen
equ esp + 8 ; s->window + bestlen
124 scanstart
equ esp + 16 ; first two bytes of string
125 scanend
equ esp + 12 ; last two bytes of string
126 scanalign
equ esp + 20 ; dword-misalignment of string
127 nicematch
equ esp + 24 ; a good enough match size
128 bestlen
equ esp + 28 ; size of best match so far
129 scan
equ esp + 32 ; ptr to string wanting match
132 ; saved ebx byte esp + 36
133 ; saved edi byte esp + 40
134 ; saved esi byte esp + 44
135 ; saved ebp byte esp + 48
136 ; return address byte esp + 52
137 deflatestate
equ esp + 56 ; the function arguments
138 curmatch
equ esp + 60
140 ;;; Offsets for fields in the deflate_state structure. These numbers
141 ;;; are calculated from the definition of deflate_state, with the
142 ;;; assumption that the compiler will dword-align the fields. (Thus,
143 ;;; changing the definition of deflate_state could easily cause this
144 ;;; program to crash horribly, without so much as a warning at
145 ;;; compile time. Sigh.)
147 dsWSize
equ 36+zlib1222add
148 dsWMask
equ 44+zlib1222add
149 dsWindow
equ 48+zlib1222add
150 dsPrev
equ 56+zlib1222add
151 dsMatchLen
equ 88+zlib1222add
152 dsPrevMatch
equ 92+zlib1222add
153 dsStrStart
equ 100+zlib1222add
154 dsMatchStart
equ 104+zlib1222add
155 dsLookahead
equ 108+zlib1222add
156 dsPrevLen
equ 112+zlib1222add
157 dsMaxChainLen
equ 116+zlib1222add
158 dsGoodMatch
equ 132+zlib1222add
159 dsNiceMatch
equ 136+zlib1222add
162 ;;; match686.asm -- Pentium-Pro-optimized version of longest_match()
163 ;;; Written for zlib 1.1.2
164 ;;; Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
165 ;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html
168 ;; This software is provided 'as-is', without any express or implied
169 ;; warranty. In no event will the authors be held liable for any damages
170 ;; arising from the use of this software.
172 ;; Permission is granted to anyone to use this software for any purpose,
173 ;; including commercial applications, and to alter it and redistribute it
174 ;; freely, subject to the following restrictions:
176 ;; 1. The origin of this software must not be misrepresented; you must not
177 ;; claim that you wrote the original software. If you use this software
178 ;; in a product, an acknowledgment in the product documentation would be
179 ;; appreciated but is not required.
180 ;; 2. Altered source versions must be plainly marked as such, and must not be
181 ;; misrepresented as being the original software
182 ;; 3. This notice may not be removed or altered from any source distribution.
185 ;GLOBAL _longest_match, _match_init
190 ;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch)
194 longest_match
proc near
196 _longest_match
proc near
199 ;;; Save registers that the compiler may be using, and adjust esp to
200 ;;; make room for our stack frame.
206 sub esp, LocalVarsSize
208 ;;; Retrieve the function arguments. ecx will hold cur_match
209 ;;; throughout the entire function. edx will hold the pointer to the
210 ;;; deflate_state structure during the function's setup (before
211 ;;; entering the main loop.
213 mov edx, [deflatestate
]
216 ;;; uInt wmask = s->w_mask;
217 ;;; unsigned chain_length = s->max_chain_length;
218 ;;; if (s->prev_length >= s->good_match) {
219 ;;; chain_length >>= 2;
222 mov eax, [edx + dsPrevLen
]
223 mov ebx, [edx + dsGoodMatch
]
225 mov eax, [edx + dsWMask
]
226 mov ebx, [edx + dsMaxChainLen
]
231 ;;; chainlen is decremented once beforehand so that the function can
232 ;;; use the sign flag instead of the zero flag for the exit test.
233 ;;; It is then shifted into the high word, to make room for the wmask
234 ;;; value, which it will always accompany.
239 mov [chainlenwmask
], ebx
241 ;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
243 mov eax, [edx + dsNiceMatch
]
244 mov ebx, [edx + dsLookahead
]
248 LookaheadLess: mov [nicematch
], ebx
250 ;;; register Bytef *scan = s->window + s->strstart;
252 mov esi, [edx + dsWindow
]
254 mov ebp, [edx + dsStrStart
]
258 ;;; Determine how many bytes the scan ptr is off from being
266 ;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
267 ;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
269 mov eax, [edx + dsWSize
]
270 sub eax, MIN_LOOKAHEAD
276 ;;; int best_len = s->prev_length;
278 mov eax, [edx + dsPrevLen
]
281 ;;; Store the sum of s->window + best_len in esi locally, and in esi.
284 mov [windowbestlen
], esi
286 ;;; register ush scan_start = *(ushf*)scan;
287 ;;; register ush scan_end = *(ushf*)(scan+best_len-1);
288 ;;; Posf *prev = s->prev;
290 movzx ebx, word ptr [edi]
292 movzx ebx, word ptr [edi + eax - 1]
294 mov edi, [edx + dsPrev
]
296 ;;; Jump into the main loop.
298 mov edx, [chainlenwmask
]
304 ;;; match = s->window + cur_match;
305 ;;; if (*(ushf*)(match+best_len-1) != scan_end ||
306 ;;; *(ushf*)match != scan_start) continue;
308 ;;; } while ((cur_match = prev[cur_match & wmask]) > limit
309 ;;; && --chain_length != 0);
311 ;;; Here is the inner loop of the function. The function will spend the
312 ;;; majority of its time in this loop, and majority of that time will
313 ;;; be spent in the first ten instructions.
315 ;;; Within this loop:
318 ;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
319 ;;; esi = windowbestlen - i.e., (window + bestlen)
325 movzx ecx, word ptr [edi + ecx*2]
330 LoopEntry: movzx eax, word ptr [esi + ecx - 1]
334 movzx eax, word ptr [eax + ecx]
338 ;;; Store the current value of chainlen.
340 mov [chainlenwmask
], edx
342 ;;; Point edi to the string under scrutiny, and esi to the string we
343 ;;; are hoping to match it up with. In actuality, esi and edi are
344 ;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
345 ;;; initialized to -(MAX_MATCH_8 - scanalign).
351 mov edx, 0fffffef8h
; -(MAX_MATCH_8)
352 lea edi, [edi + eax + 0108h] ;MAX_MATCH_8]
353 lea esi, [esi + eax + 0108h] ;MAX_MATCH_8]
355 ;;; Test the strings for equality, 8 bytes at a time. At the end,
356 ;;; adjust edx so that it is offset to the exact byte that mismatched.
358 ;;; We already know at this point that the first three bytes of the
359 ;;; strings match each other, and they can be safely passed over before
360 ;;; starting the compare loop. So what this code does is skip over 0-3
361 ;;; bytes, as much as necessary in order to dword-align the edi
362 ;;; pointer. (esi will still be misaligned three times out of four.)
364 ;;; It should be confessed that this loop usually does not represent
365 ;;; much of the total running time. Replacing it with a more
366 ;;; straightforward "rep cmpsb" would not drastically degrade
373 mov eax, [esi + edx + 4]
374 xor eax, [edi + edx + 4]
379 LeaveLoopCmps4: add edx, 4
380 LeaveLoopCmps: test eax, 0000FFFFh
387 ;;; Calculate the length of the match. If it is longer than MAX_MATCH,
388 ;;; then automatically accept it as the best possible match and leave.
396 ;;; If the length of the match is not longer than the best match we
397 ;;; have so far, then forget it and return to the lookup loop.
399 mov edx, [deflatestate
]
403 mov esi, [windowbestlen
]
404 mov edi, [edx + dsPrev
]
406 mov edx, [chainlenwmask
]
409 ;;; s->match_start = cur_match;
411 ;;; if (len >= nice_match) break;
412 ;;; scan_end = *(ushf*)(scan+best_len-1);
414 LongerMatch: mov ebx, [nicematch
]
416 mov [edx + dsMatchStart
], ecx
421 mov [windowbestlen
], esi
422 movzx ebx, word ptr [edi + eax - 1]
423 mov edi, [edx + dsPrev
]
425 mov edx, [chainlenwmask
]
428 ;;; Accept the current string, with the maximum possible length.
430 LenMaximum: mov edx, [deflatestate
]
431 mov dword ptr [bestlen
], MAX_MATCH
432 mov [edx + dsMatchStart
], ecx
434 ;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
435 ;;; return s->lookahead;
438 mov edx, [deflatestate
]
440 mov eax, [edx + dsLookahead
]
446 ;;; Restore the stack and return from whence we came.
448 add esp, LocalVarsSize
455 ; please don't remove this string !
456 ; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary!
457 db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah
471 _match_init
proc near