c++: Fix crash during NRV optimization with invalid input [PR117099, PR117129]
[official-gcc.git] / zlib / contrib / masmx86 / match686.asm
blob3b09212f8a29916959be48a7cc920d423794c60c
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
7 ; http://www.zlib.net
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)
38 ; deflate_state *s;
39 ; IPos cur_match; /* current match */
41 NbStack equ 76
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)
67 .386p
69 name gvmatch
70 .MODEL FLAT
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").
80 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
96 _TEXT segment
98 IFDEF NOUNDERLINE
99 public longest_match
100 public match_init
101 ELSE
102 public _longest_match
103 public _match_init
104 ENDIF
106 MAX_MATCH equ 258
107 MIN_MATCH equ 3
108 MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
112 MAX_MATCH equ 258
113 MIN_MATCH equ 3
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
121 ; low word: s->wmask
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
131 LocalVarsSize equ 36
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
188 ;SECTION .text
190 ;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch)
192 ;_longest_match:
193 IFDEF NOUNDERLINE
194 longest_match proc near
195 ELSE
196 _longest_match proc near
197 ENDIF
198 .FPO (9, 4, 0, 0, 1, 0)
200 ;;; Save registers that the compiler may be using, and adjust esp to
201 ;;; make room for our stack frame.
203 push ebp
204 push edi
205 push esi
206 push ebx
207 sub esp, LocalVarsSize
209 ;;; Retrieve the function arguments. ecx will hold cur_match
210 ;;; throughout the entire function. edx will hold the pointer to the
211 ;;; deflate_state structure during the function's setup (before
212 ;;; entering the main loop.
214 mov edx, [deflatestate]
215 mov ecx, [curmatch]
217 ;;; uInt wmask = s->w_mask;
218 ;;; unsigned chain_length = s->max_chain_length;
219 ;;; if (s->prev_length >= s->good_match) {
220 ;;; chain_length >>= 2;
221 ;;; }
223 mov eax, [edx + dsPrevLen]
224 mov ebx, [edx + dsGoodMatch]
225 cmp eax, ebx
226 mov eax, [edx + dsWMask]
227 mov ebx, [edx + dsMaxChainLen]
228 jl LastMatchGood
229 shr ebx, 2
230 LastMatchGood:
232 ;;; chainlen is decremented once beforehand so that the function can
233 ;;; use the sign flag instead of the zero flag for the exit test.
234 ;;; It is then shifted into the high word, to make room for the wmask
235 ;;; value, which it will always accompany.
237 dec ebx
238 shl ebx, 16
239 or ebx, eax
240 mov [chainlenwmask], ebx
242 ;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
244 mov eax, [edx + dsNiceMatch]
245 mov ebx, [edx + dsLookahead]
246 cmp ebx, eax
247 jl LookaheadLess
248 mov ebx, eax
249 LookaheadLess: mov [nicematch], ebx
251 ;;; register Bytef *scan = s->window + s->strstart;
253 mov esi, [edx + dsWindow]
254 mov [window], esi
255 mov ebp, [edx + dsStrStart]
256 lea edi, [esi + ebp]
257 mov [scan], edi
259 ;;; Determine how many bytes the scan ptr is off from being
260 ;;; dword-aligned.
262 mov eax, edi
263 neg eax
264 and eax, 3
265 mov [scanalign], eax
267 ;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
268 ;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
270 mov eax, [edx + dsWSize]
271 sub eax, MIN_LOOKAHEAD
272 sub ebp, eax
273 jg LimitPositive
274 xor ebp, ebp
275 LimitPositive:
277 ;;; int best_len = s->prev_length;
279 mov eax, [edx + dsPrevLen]
280 mov [bestlen], eax
282 ;;; Store the sum of s->window + best_len in esi locally, and in esi.
284 add esi, eax
285 mov [windowbestlen], esi
287 ;;; register ush scan_start = *(ushf*)scan;
288 ;;; register ush scan_end = *(ushf*)(scan+best_len-1);
289 ;;; Posf *prev = s->prev;
291 movzx ebx, word ptr [edi]
292 mov [scanstart], ebx
293 movzx ebx, word ptr [edi + eax - 1]
294 mov [scanend], ebx
295 mov edi, [edx + dsPrev]
297 ;;; Jump into the main loop.
299 mov edx, [chainlenwmask]
300 jmp short LoopEntry
302 align 4
304 ;;; do {
305 ;;; match = s->window + cur_match;
306 ;;; if (*(ushf*)(match+best_len-1) != scan_end ||
307 ;;; *(ushf*)match != scan_start) continue;
308 ;;; [...]
309 ;;; } while ((cur_match = prev[cur_match & wmask]) > limit
310 ;;; && --chain_length != 0);
312 ;;; Here is the inner loop of the function. The function will spend the
313 ;;; majority of its time in this loop, and majority of that time will
314 ;;; be spent in the first ten instructions.
316 ;;; Within this loop:
317 ;;; ebx = scanend
318 ;;; ecx = curmatch
319 ;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
320 ;;; esi = windowbestlen - i.e., (window + bestlen)
321 ;;; edi = prev
322 ;;; ebp = limit
324 LookupLoop:
325 and ecx, edx
326 movzx ecx, word ptr [edi + ecx*2]
327 cmp ecx, ebp
328 jbe LeaveNow
329 sub edx, 00010000h
330 js LeaveNow
331 LoopEntry: movzx eax, word ptr [esi + ecx - 1]
332 cmp eax, ebx
333 jnz LookupLoop
334 mov eax, [window]
335 movzx eax, word ptr [eax + ecx]
336 cmp eax, [scanstart]
337 jnz LookupLoop
339 ;;; Store the current value of chainlen.
341 mov [chainlenwmask], edx
343 ;;; Point edi to the string under scrutiny, and esi to the string we
344 ;;; are hoping to match it up with. In actuality, esi and edi are
345 ;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
346 ;;; initialized to -(MAX_MATCH_8 - scanalign).
348 mov esi, [window]
349 mov edi, [scan]
350 add esi, ecx
351 mov eax, [scanalign]
352 mov edx, 0fffffef8h; -(MAX_MATCH_8)
353 lea edi, [edi + eax + 0108h] ;MAX_MATCH_8]
354 lea esi, [esi + eax + 0108h] ;MAX_MATCH_8]
356 ;;; Test the strings for equality, 8 bytes at a time. At the end,
357 ;;; adjust edx so that it is offset to the exact byte that mismatched.
359 ;;; We already know at this point that the first three bytes of the
360 ;;; strings match each other, and they can be safely passed over before
361 ;;; starting the compare loop. So what this code does is skip over 0-3
362 ;;; bytes, as much as necessary in order to dword-align the edi
363 ;;; pointer. (esi will still be misaligned three times out of four.)
365 ;;; It should be confessed that this loop usually does not represent
366 ;;; much of the total running time. Replacing it with a more
367 ;;; straightforward "rep cmpsb" would not drastically degrade
368 ;;; performance.
370 LoopCmps:
371 mov eax, [esi + edx]
372 xor eax, [edi + edx]
373 jnz LeaveLoopCmps
374 mov eax, [esi + edx + 4]
375 xor eax, [edi + edx + 4]
376 jnz LeaveLoopCmps4
377 add edx, 8
378 jnz LoopCmps
379 jmp short LenMaximum
380 LeaveLoopCmps4: add edx, 4
381 LeaveLoopCmps: test eax, 0000FFFFh
382 jnz LenLower
383 add edx, 2
384 shr eax, 16
385 LenLower: sub al, 1
386 adc edx, 0
388 ;;; Calculate the length of the match. If it is longer than MAX_MATCH,
389 ;;; then automatically accept it as the best possible match and leave.
391 lea eax, [edi + edx]
392 mov edi, [scan]
393 sub eax, edi
394 cmp eax, MAX_MATCH
395 jge LenMaximum
397 ;;; If the length of the match is not longer than the best match we
398 ;;; have so far, then forget it and return to the lookup loop.
400 mov edx, [deflatestate]
401 mov ebx, [bestlen]
402 cmp eax, ebx
403 jg LongerMatch
404 mov esi, [windowbestlen]
405 mov edi, [edx + dsPrev]
406 mov ebx, [scanend]
407 mov edx, [chainlenwmask]
408 jmp LookupLoop
410 ;;; s->match_start = cur_match;
411 ;;; best_len = len;
412 ;;; if (len >= nice_match) break;
413 ;;; scan_end = *(ushf*)(scan+best_len-1);
415 LongerMatch: mov ebx, [nicematch]
416 mov [bestlen], eax
417 mov [edx + dsMatchStart], ecx
418 cmp eax, ebx
419 jge LeaveNow
420 mov esi, [window]
421 add esi, eax
422 mov [windowbestlen], esi
423 movzx ebx, word ptr [edi + eax - 1]
424 mov edi, [edx + dsPrev]
425 mov [scanend], ebx
426 mov edx, [chainlenwmask]
427 jmp LookupLoop
429 ;;; Accept the current string, with the maximum possible length.
431 LenMaximum: mov edx, [deflatestate]
432 mov dword ptr [bestlen], MAX_MATCH
433 mov [edx + dsMatchStart], ecx
435 ;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
436 ;;; return s->lookahead;
438 LeaveNow:
439 mov edx, [deflatestate]
440 mov ebx, [bestlen]
441 mov eax, [edx + dsLookahead]
442 cmp ebx, eax
443 jg LookaheadRet
444 mov eax, ebx
445 LookaheadRet:
447 ;;; Restore the stack and return from whence we came.
449 add esp, LocalVarsSize
450 pop ebx
451 pop esi
452 pop edi
453 pop ebp
456 ; please don't remove this string !
457 ; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary!
458 db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah
461 IFDEF NOUNDERLINE
462 longest_match endp
463 ELSE
464 _longest_match endp
465 ENDIF
467 IFDEF NOUNDERLINE
468 match_init proc near
470 match_init endp
471 ELSE
472 _match_init proc near
474 _match_init endp
475 ENDIF
478 _TEXT ends