source: Vago/zlib-1.2.8/contrib/masmx64/gvmat64.asm@ 1089

Last change on this file since 1089 was 1049, checked in by s10k, 8 years ago
File size: 16.1 KB
Line 
1;uInt longest_match_x64(
2; deflate_state *s,
3; IPos cur_match); /* current match */
4
5; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86_64
6; (AMD64 on Athlon 64, Opteron, Phenom
7; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7)
8; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
9;
10; File written by Gilles Vollant, by converting to assembly the longest_match
11; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
12;
13; and by taking inspiration on asm686 with masm, optimised assembly code
14; from Brian Raiter, written 1998
15;
16; This software is provided 'as-is', without any express or implied
17; warranty. In no event will the authors be held liable for any damages
18; arising from the use of this software.
19;
20; Permission is granted to anyone to use this software for any purpose,
21; including commercial applications, and to alter it and redistribute it
22; freely, subject to the following restrictions:
23;
24; 1. The origin of this software must not be misrepresented; you must not
25; claim that you wrote the original software. If you use this software
26; in a product, an acknowledgment in the product documentation would be
27; appreciated but is not required.
28; 2. Altered source versions must be plainly marked as such, and must not be
29; misrepresented as being the original software
30; 3. This notice may not be removed or altered from any source distribution.
31;
32;
33;
34; http://www.zlib.net
35; http://www.winimage.com/zLibDll
36; http://www.muppetlabs.com/~breadbox/software/assembly.html
37;
38; to compile this file for infozip Zip, I use option:
39; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm
40;
41; to compile this file for zLib, I use option:
42; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
43; Be carrefull to adapt zlib1222add below to your version of zLib
44; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change
45; value of zlib1222add later)
46;
47; This file compile with Microsoft Macro Assembler (x64) for AMD64
48;
49; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK
50;
51; (you can get Windows WDK with ml64 for AMD64 from
52; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price)
53;
54
55
56;uInt longest_match(s, cur_match)
57; deflate_state *s;
58; IPos cur_match; /* current match */
59.code
60longest_match PROC
61
62
63;LocalVarsSize equ 88
64 LocalVarsSize equ 72
65
66; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
67; free register : r14,r15
68; register can be saved : rsp
69
70 chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len
71 ; low word: s->wmask
72;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10
73;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11
74;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w
75;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx
76;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13
77;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d
78;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9
79IFDEF INFOZIP
80ELSE
81 nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size
82ENDIF
83
84save_rdi equ rsp + 24 - LocalVarsSize
85save_rsi equ rsp + 32 - LocalVarsSize
86save_rbx equ rsp + 40 - LocalVarsSize
87save_rbp equ rsp + 48 - LocalVarsSize
88save_r12 equ rsp + 56 - LocalVarsSize
89save_r13 equ rsp + 64 - LocalVarsSize
90;save_r14 equ rsp + 72 - LocalVarsSize
91;save_r15 equ rsp + 80 - LocalVarsSize
92
93
94; summary of register usage
95; scanend ebx
96; scanendw bx
97; chainlenwmask edx
98; curmatch rsi
99; curmatchd esi
100; windowbestlen r8
101; scanalign r9
102; scanalignd r9d
103; window r10
104; bestlen r11
105; bestlend r11d
106; scanstart r12d
107; scanstartw r12w
108; scan r13
109; nicematch r14d
110; limit r15
111; limitd r15d
112; prev rcx
113
114; all the +4 offsets are due to the addition of pending_buf_size (in zlib
115; in the deflate_state structure since the asm code was first written
116; (if you compile with zlib 1.0.4 or older, remove the +4).
117; Note : these value are good with a 8 bytes boundary pack structure
118
119
120 MAX_MATCH equ 258
121 MIN_MATCH equ 3
122 MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
123
124
125;;; Offsets for fields in the deflate_state structure. These numbers
126;;; are calculated from the definition of deflate_state, with the
127;;; assumption that the compiler will dword-align the fields. (Thus,
128;;; changing the definition of deflate_state could easily cause this
129;;; program to crash horribly, without so much as a warning at
130;;; compile time. Sigh.)
131
132; all the +zlib1222add offsets are due to the addition of fields
133; in zlib in the deflate_state structure since the asm code was first written
134; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
135; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
136; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
137
138
139IFDEF INFOZIP
140
141_DATA SEGMENT
142COMM window_size:DWORD
143; WMask ; 7fff
144COMM window:BYTE:010040H
145COMM prev:WORD:08000H
146; MatchLen : unused
147; PrevMatch : unused
148COMM strstart:DWORD
149COMM match_start:DWORD
150; Lookahead : ignore
151COMM prev_length:DWORD ; PrevLen
152COMM max_chain_length:DWORD
153COMM good_match:DWORD
154COMM nice_match:DWORD
155prev_ad equ OFFSET prev
156window_ad equ OFFSET window
157nicematch equ nice_match
158_DATA ENDS
159WMask equ 07fffh
160
161ELSE
162
163 IFNDEF zlib1222add
164 zlib1222add equ 8
165 ENDIF
166dsWSize equ 56+zlib1222add+(zlib1222add/2)
167dsWMask equ 64+zlib1222add+(zlib1222add/2)
168dsWindow equ 72+zlib1222add
169dsPrev equ 88+zlib1222add
170dsMatchLen equ 128+zlib1222add
171dsPrevMatch equ 132+zlib1222add
172dsStrStart equ 140+zlib1222add
173dsMatchStart equ 144+zlib1222add
174dsLookahead equ 148+zlib1222add
175dsPrevLen equ 152+zlib1222add
176dsMaxChainLen equ 156+zlib1222add
177dsGoodMatch equ 172+zlib1222add
178dsNiceMatch equ 176+zlib1222add
179
180window_size equ [ rcx + dsWSize]
181WMask equ [ rcx + dsWMask]
182window_ad equ [ rcx + dsWindow]
183prev_ad equ [ rcx + dsPrev]
184strstart equ [ rcx + dsStrStart]
185match_start equ [ rcx + dsMatchStart]
186Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip
187prev_length equ [ rcx + dsPrevLen]
188max_chain_length equ [ rcx + dsMaxChainLen]
189good_match equ [ rcx + dsGoodMatch]
190nice_match equ [ rcx + dsNiceMatch]
191ENDIF
192
193; parameter 1 in r8(deflate state s), param 2 in rdx (cur match)
194
195; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
196; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
197;
198; All registers must be preserved across the call, except for
199; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
200
201
202
203;;; Save registers that the compiler may be using, and adjust esp to
204;;; make room for our stack frame.
205
206
207;;; Retrieve the function arguments. r8d will hold cur_match
208;;; throughout the entire function. edx will hold the pointer to the
209;;; deflate_state structure during the function's setup (before
210;;; entering the main loop.
211
212; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
213
214; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
215
216 mov [save_rdi],rdi
217 mov [save_rsi],rsi
218 mov [save_rbx],rbx
219 mov [save_rbp],rbp
220IFDEF INFOZIP
221 mov r8d,ecx
222ELSE
223 mov r8d,edx
224ENDIF
225 mov [save_r12],r12
226 mov [save_r13],r13
227; mov [save_r14],r14
228; mov [save_r15],r15
229
230
231;;; uInt wmask = s->w_mask;
232;;; unsigned chain_length = s->max_chain_length;
233;;; if (s->prev_length >= s->good_match) {
234;;; chain_length >>= 2;
235;;; }
236
237 mov edi, prev_length
238 mov esi, good_match
239 mov eax, WMask
240 mov ebx, max_chain_length
241 cmp edi, esi
242 jl LastMatchGood
243 shr ebx, 2
244LastMatchGood:
245
246;;; chainlen is decremented once beforehand so that the function can
247;;; use the sign flag instead of the zero flag for the exit test.
248;;; It is then shifted into the high word, to make room for the wmask
249;;; value, which it will always accompany.
250
251 dec ebx
252 shl ebx, 16
253 or ebx, eax
254
255;;; on zlib only
256;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
257
258IFDEF INFOZIP
259 mov [chainlenwmask], ebx
260; on infozip nice_match = [nice_match]
261ELSE
262 mov eax, nice_match
263 mov [chainlenwmask], ebx
264 mov r10d, Lookahead
265 cmp r10d, eax
266 cmovnl r10d, eax
267 mov [nicematch],r10d
268ENDIF
269
270;;; register Bytef *scan = s->window + s->strstart;
271 mov r10, window_ad
272 mov ebp, strstart
273 lea r13, [r10 + rbp]
274
275;;; Determine how many bytes the scan ptr is off from being
276;;; dword-aligned.
277
278 mov r9,r13
279 neg r13
280 and r13,3
281
282;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
283;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
284IFDEF INFOZIP
285 mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1))
286ELSE
287 mov eax, window_size
288 sub eax, MIN_LOOKAHEAD
289ENDIF
290 xor edi,edi
291 sub ebp, eax
292
293 mov r11d, prev_length
294
295 cmovng ebp,edi
296
297;;; int best_len = s->prev_length;
298
299
300;;; Store the sum of s->window + best_len in esi locally, and in esi.
301
302 lea rsi,[r10+r11]
303
304;;; register ush scan_start = *(ushf*)scan;
305;;; register ush scan_end = *(ushf*)(scan+best_len-1);
306;;; Posf *prev = s->prev;
307
308 movzx r12d,word ptr [r9]
309 movzx ebx, word ptr [r9 + r11 - 1]
310
311 mov rdi, prev_ad
312
313;;; Jump into the main loop.
314
315 mov edx, [chainlenwmask]
316
317 cmp bx,word ptr [rsi + r8 - 1]
318 jz LookupLoopIsZero
319
320LookupLoop1:
321 and r8d, edx
322
323 movzx r8d, word ptr [rdi + r8*2]
324 cmp r8d, ebp
325 jbe LeaveNow
326 sub edx, 00010000h
327 js LeaveNow
328
329LoopEntry1:
330 cmp bx,word ptr [rsi + r8 - 1]
331 jz LookupLoopIsZero
332
333LookupLoop2:
334 and r8d, edx
335
336 movzx r8d, word ptr [rdi + r8*2]
337 cmp r8d, ebp
338 jbe LeaveNow
339 sub edx, 00010000h
340 js LeaveNow
341
342LoopEntry2:
343 cmp bx,word ptr [rsi + r8 - 1]
344 jz LookupLoopIsZero
345
346LookupLoop4:
347 and r8d, edx
348
349 movzx r8d, word ptr [rdi + r8*2]
350 cmp r8d, ebp
351 jbe LeaveNow
352 sub edx, 00010000h
353 js LeaveNow
354
355LoopEntry4:
356
357 cmp bx,word ptr [rsi + r8 - 1]
358 jnz LookupLoop1
359 jmp LookupLoopIsZero
360
361
362;;; do {
363;;; match = s->window + cur_match;
364;;; if (*(ushf*)(match+best_len-1) != scan_end ||
365;;; *(ushf*)match != scan_start) continue;
366;;; [...]
367;;; } while ((cur_match = prev[cur_match & wmask]) > limit
368;;; && --chain_length != 0);
369;;;
370;;; Here is the inner loop of the function. The function will spend the
371;;; majority of its time in this loop, and majority of that time will
372;;; be spent in the first ten instructions.
373;;;
374;;; Within this loop:
375;;; ebx = scanend
376;;; r8d = curmatch
377;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
378;;; esi = windowbestlen - i.e., (window + bestlen)
379;;; edi = prev
380;;; ebp = limit
381
382LookupLoop:
383 and r8d, edx
384
385 movzx r8d, word ptr [rdi + r8*2]
386 cmp r8d, ebp
387 jbe LeaveNow
388 sub edx, 00010000h
389 js LeaveNow
390
391LoopEntry:
392
393 cmp bx,word ptr [rsi + r8 - 1]
394 jnz LookupLoop1
395LookupLoopIsZero:
396 cmp r12w, word ptr [r10 + r8]
397 jnz LookupLoop1
398
399
400;;; Store the current value of chainlen.
401 mov [chainlenwmask], edx
402
403;;; Point edi to the string under scrutiny, and esi to the string we
404;;; are hoping to match it up with. In actuality, esi and edi are
405;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
406;;; initialized to -(MAX_MATCH_8 - scanalign).
407
408 lea rsi,[r8+r10]
409 mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8)
410 lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8]
411 lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8]
412
413 prefetcht1 [rsi+rdx]
414 prefetcht1 [rdi+rdx]
415
416
417;;; Test the strings for equality, 8 bytes at a time. At the end,
418;;; adjust rdx so that it is offset to the exact byte that mismatched.
419;;;
420;;; We already know at this point that the first three bytes of the
421;;; strings match each other, and they can be safely passed over before
422;;; starting the compare loop. So what this code does is skip over 0-3
423;;; bytes, as much as necessary in order to dword-align the edi
424;;; pointer. (rsi will still be misaligned three times out of four.)
425;;;
426;;; It should be confessed that this loop usually does not represent
427;;; much of the total running time. Replacing it with a more
428;;; straightforward "rep cmpsb" would not drastically degrade
429;;; performance.
430
431
432LoopCmps:
433 mov rax, [rsi + rdx]
434 xor rax, [rdi + rdx]
435 jnz LeaveLoopCmps
436
437 mov rax, [rsi + rdx + 8]
438 xor rax, [rdi + rdx + 8]
439 jnz LeaveLoopCmps8
440
441
442 mov rax, [rsi + rdx + 8+8]
443 xor rax, [rdi + rdx + 8+8]
444 jnz LeaveLoopCmps16
445
446 add rdx,8+8+8
447
448 jnz short LoopCmps
449 jmp short LenMaximum
450LeaveLoopCmps16: add rdx,8
451LeaveLoopCmps8: add rdx,8
452LeaveLoopCmps:
453
454 test eax, 0000FFFFh
455 jnz LenLower
456
457 test eax,0ffffffffh
458
459 jnz LenLower32
460
461 add rdx,4
462 shr rax,32
463 or ax,ax
464 jnz LenLower
465
466LenLower32:
467 shr eax,16
468 add rdx,2
469LenLower: sub al, 1
470 adc rdx, 0
471;;; Calculate the length of the match. If it is longer than MAX_MATCH,
472;;; then automatically accept it as the best possible match and leave.
473
474 lea rax, [rdi + rdx]
475 sub rax, r9
476 cmp eax, MAX_MATCH
477 jge LenMaximum
478
479;;; If the length of the match is not longer than the best match we
480;;; have so far, then forget it and return to the lookup loop.
481;///////////////////////////////////
482
483 cmp eax, r11d
484 jg LongerMatch
485
486 lea rsi,[r10+r11]
487
488 mov rdi, prev_ad
489 mov edx, [chainlenwmask]
490 jmp LookupLoop
491
492;;; s->match_start = cur_match;
493;;; best_len = len;
494;;; if (len >= nice_match) break;
495;;; scan_end = *(ushf*)(scan+best_len-1);
496
497LongerMatch:
498 mov r11d, eax
499 mov match_start, r8d
500 cmp eax, [nicematch]
501 jge LeaveNow
502
503 lea rsi,[r10+rax]
504
505 movzx ebx, word ptr [r9 + rax - 1]
506 mov rdi, prev_ad
507 mov edx, [chainlenwmask]
508 jmp LookupLoop
509
510;;; Accept the current string, with the maximum possible length.
511
512LenMaximum:
513 mov r11d,MAX_MATCH
514 mov match_start, r8d
515
516;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
517;;; return s->lookahead;
518
519LeaveNow:
520IFDEF INFOZIP
521 mov eax,r11d
522ELSE
523 mov eax, Lookahead
524 cmp r11d, eax
525 cmovng eax, r11d
526ENDIF
527
528;;; Restore the stack and return from whence we came.
529
530
531 mov rsi,[save_rsi]
532 mov rdi,[save_rdi]
533 mov rbx,[save_rbx]
534 mov rbp,[save_rbp]
535 mov r12,[save_r12]
536 mov r13,[save_r13]
537; mov r14,[save_r14]
538; mov r15,[save_r15]
539
540
541 ret 0
542; please don't remove this string !
543; Your can freely use gvmat64 in any free or commercial app
544; but it is far better don't remove the string in the binary!
545 db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0
546longest_match ENDP
547
548match_init PROC
549 ret 0
550match_init ENDP
551
552
553END
Note: See TracBrowser for help on using the repository browser.