gvmat64.asm 16 KB

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