199767f8919635c4928607450d9e0abb932109ceToomas Soome;uInt longest_match_x64(
199767f8919635c4928607450d9e0abb932109ceToomas Soome; deflate_state *s,
199767f8919635c4928607450d9e0abb932109ceToomas Soome; IPos cur_match); // current match
199767f8919635c4928607450d9e0abb932109ceToomas Soome; gvmat64.S -- Asm portion of the optimized longest_match for 32 bits x86_64
199767f8919635c4928607450d9e0abb932109ceToomas Soome; (AMD64 on Athlon 64, Opteron, Phenom
199767f8919635c4928607450d9e0abb932109ceToomas Soome; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7)
199767f8919635c4928607450d9e0abb932109ceToomas Soome; this file is translation from gvmat64.asm to GCC 4.x (for Linux, Mac XCode)
199767f8919635c4928607450d9e0abb932109ceToomas Soome; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
199767f8919635c4928607450d9e0abb932109ceToomas Soome; File written by Gilles Vollant, by converting to assembly the longest_match
199767f8919635c4928607450d9e0abb932109ceToomas Soome; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
199767f8919635c4928607450d9e0abb932109ceToomas Soome; and by taking inspiration on asm686 with masm, optimised assembly code
199767f8919635c4928607450d9e0abb932109ceToomas Soome; from Brian Raiter, written 1998
199767f8919635c4928607450d9e0abb932109ceToomas Soome; This software is provided 'as-is', without any express or implied
199767f8919635c4928607450d9e0abb932109ceToomas Soome; warranty. In no event will the authors be held liable for any damages
199767f8919635c4928607450d9e0abb932109ceToomas Soome; arising from the use of this software.
199767f8919635c4928607450d9e0abb932109ceToomas Soome; Permission is granted to anyone to use this software for any purpose,
199767f8919635c4928607450d9e0abb932109ceToomas Soome; including commercial applications, and to alter it and redistribute it
199767f8919635c4928607450d9e0abb932109ceToomas Soome; freely, subject to the following restrictions:
199767f8919635c4928607450d9e0abb932109ceToomas Soome; 1. The origin of this software must not be misrepresented; you must not
199767f8919635c4928607450d9e0abb932109ceToomas Soome; claim that you wrote the original software. If you use this software
199767f8919635c4928607450d9e0abb932109ceToomas Soome; in a product, an acknowledgment in the product documentation would be
199767f8919635c4928607450d9e0abb932109ceToomas Soome; appreciated but is not required.
199767f8919635c4928607450d9e0abb932109ceToomas Soome; 2. Altered source versions must be plainly marked as such, and must not be
199767f8919635c4928607450d9e0abb932109ceToomas Soome; misrepresented as being the original software
199767f8919635c4928607450d9e0abb932109ceToomas Soome; 3. This notice may not be removed or altered from any source distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome; http://www.muppetlabs.com/~breadbox/software/assembly.html
199767f8919635c4928607450d9e0abb932109ceToomas Soome; to compile this file for zLib, I use option:
199767f8919635c4928607450d9e0abb932109ceToomas Soome; gcc -c -arch x86_64 gvmat64.S
199767f8919635c4928607450d9e0abb932109ceToomas Soome;uInt longest_match(s, cur_match)
199767f8919635c4928607450d9e0abb932109ceToomas Soome; deflate_state *s;
199767f8919635c4928607450d9e0abb932109ceToomas Soome; IPos cur_match; // current match /
199767f8919635c4928607450d9e0abb932109ceToomas Soome; with XCode for Mac, I had strange error with some jump on intel syntax
199767f8919635c4928607450d9e0abb932109ceToomas Soome; this is why BEFORE_JMP and AFTER_JMP are used
199767f8919635c4928607450d9e0abb932109ceToomas Soome; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
199767f8919635c4928607450d9e0abb932109ceToomas Soome; free register : r14,r15
199767f8919635c4928607450d9e0abb932109ceToomas Soome; register can be saved : rsp
199767f8919635c4928607450d9e0abb932109ceToomas Soome; all the +4 offsets are due to the addition of pending_buf_size (in zlib
199767f8919635c4928607450d9e0abb932109ceToomas Soome; in the deflate_state structure since the asm code was first written
199767f8919635c4928607450d9e0abb932109ceToomas Soome; (if you compile with zlib 1.0.4 or older, remove the +4).
199767f8919635c4928607450d9e0abb932109ceToomas Soome; Note : these value are good with a 8 bytes boundary pack structure
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; Offsets for fields in the deflate_state structure. These numbers
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; are calculated from the definition of deflate_state, with the
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; assumption that the compiler will dword-align the fields. (Thus,
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; changing the definition of deflate_state could easily cause this
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; program to crash horribly, without so much as a warning at
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; compile time. Sigh.)
199767f8919635c4928607450d9e0abb932109ceToomas Soome; all the +zlib1222add offsets are due to the addition of fields
199767f8919635c4928607450d9e0abb932109ceToomas Soome; in zlib in the deflate_state structure since the asm code was first written
199767f8919635c4928607450d9e0abb932109ceToomas Soome; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
199767f8919635c4928607450d9e0abb932109ceToomas Soome; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
199767f8919635c4928607450d9e0abb932109ceToomas Soome; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* you can check the structure offset by running
199767f8919635c4928607450d9e0abb932109ceToomas Soomevoid print_depl()
199767f8919635c4928607450d9e0abb932109ceToomas Soomedeflate_state ds;
199767f8919635c4928607450d9e0abb932109ceToomas Soomedeflate_state *s=&ds;
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("size pointer=%u\n",(int)sizeof(void*));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsWSize %u\n",(int)(((char*)&(s->w_size))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsWMask %u\n",(int)(((char*)&(s->w_mask))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsWindow %u\n",(int)(((char*)&(s->window))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsPrev %u\n",(int)(((char*)&(s->prev))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsMatchLen %u\n",(int)(((char*)&(s->match_length))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsPrevMatch %u\n",(int)(((char*)&(s->prev_match))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsStrStart %u\n",(int)(((char*)&(s->strstart))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsMatchStart %u\n",(int)(((char*)&(s->match_start))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsLookahead %u\n",(int)(((char*)&(s->lookahead))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsPrevLen %u\n",(int)(((char*)&(s->prev_length))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsMaxChainLen %u\n",(int)(((char*)&(s->max_chain_length))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsGoodMatch %u\n",(int)(((char*)&(s->good_match))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soomeprintf("#define dsNiceMatch %u\n",(int)(((char*)&(s->nice_match))-((char*)s)));
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define Lookahead [ rcx + dsLookahead] //; 0ffffffffh on infozip
199767f8919635c4928607450d9e0abb932109ceToomas Soome; parameter 1 in rcx(deflate state s), param 2 in rdx (cur match)
199767f8919635c4928607450d9e0abb932109ceToomas Soome; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
199767f8919635c4928607450d9e0abb932109ceToomas Soome; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
199767f8919635c4928607450d9e0abb932109ceToomas Soome; All registers must be preserved across the call, except for
199767f8919635c4928607450d9e0abb932109ceToomas Soome; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
199767f8919635c4928607450d9e0abb932109ceToomas Soome; gcc on macosx-linux:
199767f8919635c4928607450d9e0abb932109ceToomas Soome; see http://www.x86-64.org/documentation/abi-0.99.pdf
199767f8919635c4928607450d9e0abb932109ceToomas Soome; param 1 in rdi, param 2 in rsi
199767f8919635c4928607450d9e0abb932109ceToomas Soome; rbx, rsp, rbp, r12 to r15 must be preserved
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; Save registers that the compiler may be using, and adjust esp to
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; make room for our stack frame.
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; Retrieve the function arguments. r8d will hold cur_match
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; throughout the entire function. edx will hold the pointer to the
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; deflate_state structure during the function's setup (before
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; entering the main loop.
199767f8919635c4928607450d9e0abb932109ceToomas Soome; ms: parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
199767f8919635c4928607450d9e0abb932109ceToomas Soome; mac: param 1 in rdi, param 2 rsi
199767f8919635c4928607450d9e0abb932109ceToomas Soome; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; uInt wmask = s->w_mask;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; unsigned chain_length = s->max_chain_length;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; if (s->prev_length >= s->good_match) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; chain_length >>= 2;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; chainlen is decremented once beforehand so that the function can
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; use the sign flag instead of the zero flag for the exit test.
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; It is then shifted into the high word, to make room for the wmask
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; value, which it will always accompany.
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; on zlib only
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; register Bytef *scan = s->window + s->strstart;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Determine how many bytes the scan ptr is off from being
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; dword-aligned.
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; int best_len = s->prev_length;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Store the sum of s->window + best_len in esi locally, and in esi.
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; register ush scan_start = *(ushf*)scan;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; register ush scan_end = *(ushf*)(scan+best_len-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Posf *prev = s->prev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Jump into the main loop.
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; match = s->window + cur_match;
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; if (*(ushf*)(match+best_len-1) != scan_end ||
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; *(ushf*)match != scan_start) continue;
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; } while ((cur_match = prev[cur_match & wmask]) > limit
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; && --chain_length != 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; Here is the inner loop of the function. The function will spend the
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; majority of its time in this loop, and majority of that time will
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; be spent in the first ten instructions.
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; Within this loop:
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; ebx = scanend
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; r8d = curmatch
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; esi = windowbestlen - i.e., (window + bestlen)
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; edi = prev
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; ebp = limit
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Store the current value of chainlen.
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; Point edi to the string under scrutiny, and esi to the string we
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; are hoping to match it up with. In actuality, esi and edi are
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; initialized to -(MAX_MATCH_8 - scanalign).
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; Test the strings for equality, 8 bytes at a time. At the end,
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; adjust rdx so that it is offset to the exact byte that mismatched.
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; We already know at this point that the first three bytes of the
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; strings match each other, and they can be safely passed over before
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; starting the compare loop. So what this code does is skip over 0-3
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; bytes, as much as necessary in order to dword-align the edi
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; pointer. (rsi will still be misaligned three times out of four.)
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; It should be confessed that this loop usually does not represent
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; much of the total running time. Replacing it with a more
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; straightforward "rep cmpsb" would not drastically degrade
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; performance.
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Calculate the length of the match. If it is longer than MAX_MATCH,
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; then automatically accept it as the best possible match and leave.
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; If the length of the match is not longer than the best match we
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; have so far, then forget it and return to the lookup loop.
199767f8919635c4928607450d9e0abb932109ceToomas Soome;///////////////////////////////////
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; s->match_start = cur_match;
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; best_len = len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; if (len >= nice_match) break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome;;; scan_end = *(ushf*)(scan+best_len-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Accept the current string, with the maximum possible length.
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; return s->lookahead;
199767f8919635c4928607450d9e0abb932109ceToomas Soome//;;; Restore the stack and return from whence we came.
199767f8919635c4928607450d9e0abb932109ceToomas Soome// mov rsi,[save_rsi]
199767f8919635c4928607450d9e0abb932109ceToomas Soome// mov rdi,[save_rdi]
199767f8919635c4928607450d9e0abb932109ceToomas Soome//; please don't remove this string !
199767f8919635c4928607450d9e0abb932109ceToomas Soome//; Your can freely use gvmat64 in any free or commercial app
199767f8919635c4928607450d9e0abb932109ceToomas Soome//; but it is far better don't remove the string in the binary!
199767f8919635c4928607450d9e0abb932109ceToomas Soome // 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