URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [zlib/] [contrib/] [masmx64/] [gvmat64.asm] - Rev 745
Compare with Previous | Blame | View Log
;uInt longest_match_x64(; deflate_state *s,; IPos cur_match); /* current match */; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86; Copyright (C) 1995-2005 Jean-loup Gailly, Brian Raiter and Gilles Vollant.;; File written by Gilles Vollant, by converting to assembly the longest_match; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.;; and by taking inspiration on asm686 with masm, optimised assembly code; from Brian Raiter, written 1998;; http://www.zlib.net; http://www.winimage.com/zLibDll; http://www.muppetlabs.com/~breadbox/software/assembly.html;; to compile this file for infozip Zip, I use option:; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm;; to compile this file for zLib, I use option:; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm; Be carrefull to adapt zlib1222add below to your version of zLib; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change; value of zlib1222add later);; This file compile with Microsoft Macro Assembler (x64) for AMD64;; ml64.exe is given with Visual Studio 2005 and Windows 2003 server DDK;; (you can get Windows 2003 server DDK with ml64 and cl for AMD64 from; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price);;uInt longest_match(s, cur_match); deflate_state *s;; IPos cur_match; /* current match */.codelongest_match PROC;LocalVarsSize equ 88LocalVarsSize equ 72; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12; free register : r14,r15; register can be saved : rspchainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len; low word: s->wmask;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9IFDEF INFOZIPELSEnicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match sizeENDIFsave_rdi equ rsp + 24 - LocalVarsSizesave_rsi equ rsp + 32 - LocalVarsSizesave_rbx equ rsp + 40 - LocalVarsSizesave_rbp equ rsp + 48 - LocalVarsSizesave_r12 equ rsp + 56 - LocalVarsSizesave_r13 equ rsp + 64 - LocalVarsSize;save_r14 equ rsp + 72 - LocalVarsSize;save_r15 equ rsp + 80 - LocalVarsSize; all the +4 offsets are due to the addition of pending_buf_size (in zlib; in the deflate_state structure since the asm code was first written; (if you compile with zlib 1.0.4 or older, remove the +4).; Note : these value are good with a 8 bytes boundary pack structureMAX_MATCH equ 258MIN_MATCH equ 3MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1);;; Offsets for fields in the deflate_state structure. These numbers;;; are calculated from the definition of deflate_state, with the;;; assumption that the compiler will dword-align the fields. (Thus,;;; changing the definition of deflate_state could easily cause this;;; program to crash horribly, without so much as a warning at;;; compile time. Sigh.); all the +zlib1222add offsets are due to the addition of fields; in zlib in the deflate_state structure since the asm code was first written; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").IFDEF INFOZIP_DATA SEGMENTCOMM window_size:DWORD; WMask ; 7fffCOMM window:BYTE:010040HCOMM prev:WORD:08000H; MatchLen : unused; PrevMatch : unusedCOMM strstart:DWORDCOMM match_start:DWORD; Lookahead : ignoreCOMM prev_length:DWORD ; PrevLenCOMM max_chain_length:DWORDCOMM good_match:DWORDCOMM nice_match:DWORDprev_ad equ OFFSET prevwindow_ad equ OFFSET windownicematch equ nice_match_DATA ENDSWMask equ 07fffhELSEIFNDEF zlib1222addzlib1222add equ 8ENDIFdsWSize equ 56+zlib1222add+(zlib1222add/2)dsWMask equ 64+zlib1222add+(zlib1222add/2)dsWindow equ 72+zlib1222adddsPrev equ 88+zlib1222adddsMatchLen equ 128+zlib1222adddsPrevMatch equ 132+zlib1222adddsStrStart equ 140+zlib1222adddsMatchStart equ 144+zlib1222adddsLookahead equ 148+zlib1222adddsPrevLen equ 152+zlib1222adddsMaxChainLen equ 156+zlib1222adddsGoodMatch equ 172+zlib1222adddsNiceMatch equ 176+zlib1222addwindow_size equ [ rcx + dsWSize]WMask equ [ rcx + dsWMask]window_ad equ [ rcx + dsWindow]prev_ad equ [ rcx + dsPrev]strstart equ [ rcx + dsStrStart]match_start equ [ rcx + dsMatchStart]Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozipprev_length equ [ rcx + dsPrevLen]max_chain_length equ [ rcx + dsMaxChainLen]good_match equ [ rcx + dsGoodMatch]nice_match equ [ rcx + dsNiceMatch]ENDIF; parameter 1 in r8(deflate state s), param 2 in rdx (cur match); see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp;; All registers must be preserved across the call, except for; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.;;; Save registers that the compiler may be using, and adjust esp to;;; make room for our stack frame.;;; Retrieve the function arguments. r8d will hold cur_match;;; throughout the entire function. edx will hold the pointer to the;;; deflate_state structure during the function's setup (before;;; entering the main loop.; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match); this clear high 32 bits of r8, which can be garbage in both r8 and rdxmov [save_rdi],rdimov [save_rsi],rsimov [save_rbx],rbxmov [save_rbp],rbpIFDEF INFOZIPmov r8d,ecxELSEmov r8d,edxENDIFmov [save_r12],r12mov [save_r13],r13; mov [save_r14],r14; mov [save_r15],r15;;; uInt wmask = s->w_mask;;;; unsigned chain_length = s->max_chain_length;;;; if (s->prev_length >= s->good_match) {;;; chain_length >>= 2;;;; }mov edi, prev_lengthmov esi, good_matchmov eax, WMaskmov ebx, max_chain_lengthcmp edi, esijl LastMatchGoodshr ebx, 2LastMatchGood:;;; chainlen is decremented once beforehand so that the function can;;; use the sign flag instead of the zero flag for the exit test.;;; It is then shifted into the high word, to make room for the wmask;;; value, which it will always accompany.dec ebxshl ebx, 16or ebx, eax;;; on zlib only;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;IFDEF INFOZIPmov [chainlenwmask], ebx; on infozip nice_match = [nice_match]ELSEmov eax, nice_matchmov [chainlenwmask], ebxmov r10d, Lookaheadcmp r10d, eaxcmovnl r10d, eaxmov [nicematch],r10dENDIF;;; register Bytef *scan = s->window + s->strstart;mov r10, window_admov ebp, strstartlea r13, [r10 + rbp];;; Determine how many bytes the scan ptr is off from being;;; dword-aligned.mov r9,r13neg r13and r13,3;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?;;; s->strstart - (IPos)MAX_DIST(s) : NIL;IFDEF INFOZIPmov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1))ELSEmov eax, window_sizesub eax, MIN_LOOKAHEADENDIFxor edi,edisub ebp, eaxmov r11d, prev_lengthcmovng ebp,edi;;; int best_len = s->prev_length;;;; Store the sum of s->window + best_len in esi locally, and in esi.lea rsi,[r10+r11];;; register ush scan_start = *(ushf*)scan;;;; register ush scan_end = *(ushf*)(scan+best_len-1);;;; Posf *prev = s->prev;movzx r12d,word ptr [r9]movzx ebx, word ptr [r9 + r11 - 1]mov rdi, prev_ad;;; Jump into the main loop.mov edx, [chainlenwmask]cmp bx,word ptr [rsi + r8 - 1]jz LookupLoopIsZeroLookupLoop1:and r8d, edxmovzx r8d, word ptr [rdi + r8*2]cmp r8d, ebpjbe LeaveNowsub edx, 00010000hjs LeaveNowLoopEntry1:cmp bx,word ptr [rsi + r8 - 1]jz LookupLoopIsZeroLookupLoop2:and r8d, edxmovzx r8d, word ptr [rdi + r8*2]cmp r8d, ebpjbe LeaveNowsub edx, 00010000hjs LeaveNowLoopEntry2:cmp bx,word ptr [rsi + r8 - 1]jz LookupLoopIsZeroLookupLoop4:and r8d, edxmovzx r8d, word ptr [rdi + r8*2]cmp r8d, ebpjbe LeaveNowsub edx, 00010000hjs LeaveNowLoopEntry4:cmp bx,word ptr [rsi + r8 - 1]jnz LookupLoop1jmp LookupLoopIsZero;;; do {;;; match = s->window + cur_match;;;; if (*(ushf*)(match+best_len-1) != scan_end ||;;; *(ushf*)match != scan_start) continue;;;; [...];;; } while ((cur_match = prev[cur_match & wmask]) > limit;;; && --chain_length != 0);;;;;;; Here is the inner loop of the function. The function will spend the;;; majority of its time in this loop, and majority of that time will;;; be spent in the first ten instructions.;;;;;; Within this loop:;;; ebx = scanend;;; r8d = curmatch;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask);;; esi = windowbestlen - i.e., (window + bestlen);;; edi = prev;;; ebp = limitLookupLoop:and r8d, edxmovzx r8d, word ptr [rdi + r8*2]cmp r8d, ebpjbe LeaveNowsub edx, 00010000hjs LeaveNowLoopEntry:cmp bx,word ptr [rsi + r8 - 1]jnz LookupLoop1LookupLoopIsZero:cmp r12w, word ptr [r10 + r8]jnz LookupLoop1;;; Store the current value of chainlen.mov [chainlenwmask], edx;;; Point edi to the string under scrutiny, and esi to the string we;;; are hoping to match it up with. In actuality, esi and edi are;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is;;; initialized to -(MAX_MATCH_8 - scanalign).lea rsi,[r8+r10]mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8)lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8]lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8]prefetcht1 [rsi+rdx]prefetcht1 [rdi+rdx];;; Test the strings for equality, 8 bytes at a time. At the end,;;; adjust rdx so that it is offset to the exact byte that mismatched.;;;;;; We already know at this point that the first three bytes of the;;; strings match each other, and they can be safely passed over before;;; starting the compare loop. So what this code does is skip over 0-3;;; bytes, as much as necessary in order to dword-align the edi;;; pointer. (rsi will still be misaligned three times out of four.);;;;;; It should be confessed that this loop usually does not represent;;; much of the total running time. Replacing it with a more;;; straightforward "rep cmpsb" would not drastically degrade;;; performance.LoopCmps:mov rax, [rsi + rdx]xor rax, [rdi + rdx]jnz LeaveLoopCmpsmov rax, [rsi + rdx + 8]xor rax, [rdi + rdx + 8]jnz LeaveLoopCmps8mov rax, [rsi + rdx + 8+8]xor rax, [rdi + rdx + 8+8]jnz LeaveLoopCmps16add rdx,8+8+8jmp short LoopCmpsLeaveLoopCmps16: add rdx,8LeaveLoopCmps8: add rdx,8LeaveLoopCmps:test eax, 0000FFFFhjnz LenLowertest eax,0ffffffffhjnz LenLower32add rdx,4shr rax,32or ax,axjnz LenLowerLenLower32:shr eax,16add rdx,2LenLower: sub al, 1adc rdx, 0;;; Calculate the length of the match. If it is longer than MAX_MATCH,;;; then automatically accept it as the best possible match and leave.lea rax, [rdi + rdx]sub rax, r9cmp eax, MAX_MATCHjge LenMaximum;;; If the length of the match is not longer than the best match we;;; have so far, then forget it and return to the lookup loop.;///////////////////////////////////cmp eax, r11djg LongerMatchlea rsi,[r10+r11]mov rdi, prev_admov edx, [chainlenwmask]jmp LookupLoop;;; s->match_start = cur_match;;;; best_len = len;;;; if (len >= nice_match) break;;;; scan_end = *(ushf*)(scan+best_len-1);LongerMatch:mov r11d, eaxmov match_start, r8dcmp eax, [nicematch]jge LeaveNowlea rsi,[r10+rax]movzx ebx, word ptr [r9 + rax - 1]mov rdi, prev_admov edx, [chainlenwmask]jmp LookupLoop;;; Accept the current string, with the maximum possible length.LenMaximum:mov r11d,MAX_MATCHmov match_start, r8d;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;;;; return s->lookahead;LeaveNow:IFDEF INFOZIPmov eax,r11dELSEmov eax, Lookaheadcmp r11d, eaxcmovng eax, r11dENDIF;;; Restore the stack and return from whence we came.mov rsi,[save_rsi]mov rdi,[save_rdi]mov rbx,[save_rbx]mov rbp,[save_rbp]mov r12,[save_r12]mov r13,[save_r13]; mov r14,[save_r14]; mov r15,[save_r15]ret 0; please don't remove this string !; Your can freely use gvmat64 in any free or commercial app; but it is far better don't remove the string in the binary!db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0longest_match ENDPmatch_init PROCret 0match_init ENDPEND
