third_party/zlib: Initial copy of zlib.
[bbaumbach/samba-autobuild/.git] / third_party / zlib / contrib / masmx64 / inffasx64.asm
1 ; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding\r
2 ; version for AMD64 on Windows using Microsoft C compiler\r
3 ;\r
4 ; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c\r
5 ; inffasx64.asm is called by inffas8664.c, which contain more info.\r
6 \r
7 \r
8 ; to compile this file, I use option\r
9 ;   ml64.exe /Flinffasx64 /c /Zi inffasx64.asm\r
10 ;   with Microsoft Macro Assembler (x64) for AMD64\r
11 ;\r
12 ;   ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK\r
13 ;\r
14 ;   (you can get Windows 2003 server DDK with ml64 and cl.exe for AMD64 from \r
15 ;      http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)\r
16 ;\r
17 \r
18 .code\r
19 inffas8664fnc PROC\r
20 \r
21 ; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and\r
22 ; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp\r
23 ;\r
24 ; All registers must be preserved across the call, except for\r
25 ;   rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch.\r
26 \r
27 \r
28         mov [rsp-8],rsi\r
29         mov [rsp-16],rdi\r
30         mov [rsp-24],r12\r
31         mov [rsp-32],r13\r
32         mov [rsp-40],r14\r
33         mov [rsp-48],r15\r
34         mov [rsp-56],rbx\r
35 \r
36         mov rax,rcx\r
37 \r
38         mov     [rax+8], rbp       ; /* save regs rbp and rsp */\r
39         mov     [rax], rsp\r
40 \r
41         mov     rsp, rax          ; /* make rsp point to &ar */\r
42 \r
43         mov     rsi, [rsp+16]      ; /* rsi  = in */\r
44         mov     rdi, [rsp+32]      ; /* rdi  = out */\r
45         mov     r9, [rsp+24]       ; /* r9   = last */\r
46         mov     r10, [rsp+48]      ; /* r10  = end */\r
47         mov     rbp, [rsp+64]      ; /* rbp  = lcode */\r
48         mov     r11, [rsp+72]      ; /* r11  = dcode */\r
49         mov     rdx, [rsp+80]      ; /* rdx  = hold */\r
50         mov     ebx, [rsp+88]      ; /* ebx  = bits */\r
51         mov     r12d, [rsp+100]    ; /* r12d = lmask */\r
52         mov     r13d, [rsp+104]    ; /* r13d = dmask */\r
53                                           ; /* r14d = len */\r
54                                           ; /* r15d = dist */\r
55 \r
56 \r
57         cld\r
58         cmp     r10, rdi\r
59         je      L_one_time           ; /* if only one decode left */\r
60         cmp     r9, rsi\r
61 \r
62     jne L_do_loop\r
63 \r
64 \r
65 L_one_time:\r
66         mov     r8, r12           ; /* r8 = lmask */\r
67         cmp     bl, 32\r
68         ja      L_get_length_code_one_time\r
69 \r
70         lodsd                         ; /* eax = *(uint *)in++ */\r
71         mov     cl, bl            ; /* cl = bits, needs it for shifting */\r
72         add     bl, 32             ; /* bits += 32 */\r
73         shl     rax, cl\r
74         or      rdx, rax          ; /* hold |= *((uint *)in)++ << bits */\r
75         jmp     L_get_length_code_one_time\r
76 \r
77 ALIGN 4\r
78 L_while_test:\r
79         cmp     r10, rdi\r
80         jbe     L_break_loop\r
81         cmp     r9, rsi\r
82         jbe     L_break_loop\r
83 \r
84 L_do_loop:\r
85         mov     r8, r12           ; /* r8 = lmask */\r
86         cmp     bl, 32\r
87         ja      L_get_length_code    ; /* if (32 < bits) */\r
88 \r
89         lodsd                         ; /* eax = *(uint *)in++ */\r
90         mov     cl, bl            ; /* cl = bits, needs it for shifting */\r
91         add     bl, 32             ; /* bits += 32 */\r
92         shl     rax, cl\r
93         or      rdx, rax          ; /* hold |= *((uint *)in)++ << bits */\r
94 \r
95 L_get_length_code:\r
96         and     r8, rdx            ; /* r8 &= hold */\r
97         mov     eax, [rbp+r8*4]  ; /* eax = lcode[hold & lmask] */\r
98 \r
99         mov     cl, ah            ; /* cl = this.bits */\r
100         sub     bl, ah            ; /* bits -= this.bits */\r
101         shr     rdx, cl           ; /* hold >>= this.bits */\r
102 \r
103         test    al, al\r
104         jnz     L_test_for_length_base ; /* if (op != 0) 45.7% */\r
105 \r
106         mov     r8, r12            ; /* r8 = lmask */\r
107         shr     eax, 16            ; /* output this.val char */\r
108         stosb\r
109 \r
110 L_get_length_code_one_time:\r
111         and     r8, rdx            ; /* r8 &= hold */\r
112         mov     eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */\r
113 \r
114 L_dolen:\r
115         mov     cl, ah            ; /* cl = this.bits */\r
116         sub     bl, ah            ; /* bits -= this.bits */\r
117         shr     rdx, cl           ; /* hold >>= this.bits */\r
118 \r
119         test    al, al\r
120         jnz     L_test_for_length_base ; /* if (op != 0) 45.7% */\r
121 \r
122         shr     eax, 16            ; /* output this.val char */\r
123         stosb\r
124         jmp     L_while_test\r
125 \r
126 ALIGN 4\r
127 L_test_for_length_base:\r
128         mov     r14d, eax         ; /* len = this */\r
129         shr     r14d, 16           ; /* len = this.val */\r
130         mov     cl, al\r
131 \r
132         test    al, 16\r
133         jz      L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */\r
134         and     cl, 15             ; /* op &= 15 */\r
135         jz      L_decode_distance    ; /* if (!op) */\r
136 \r
137 L_add_bits_to_len:\r
138         sub     bl, cl\r
139         xor     eax, eax\r
140         inc     eax\r
141         shl     eax, cl\r
142         dec     eax\r
143         and     eax, edx          ; /* eax &= hold */\r
144         shr     rdx, cl\r
145         add     r14d, eax         ; /* len += hold & mask[op] */\r
146 \r
147 L_decode_distance:\r
148         mov     r8, r13           ; /* r8 = dmask */\r
149         cmp     bl, 32\r
150         ja      L_get_distance_code  ; /* if (32 < bits) */\r
151 \r
152         lodsd                         ; /* eax = *(uint *)in++ */\r
153         mov     cl, bl            ; /* cl = bits, needs it for shifting */\r
154         add     bl, 32             ; /* bits += 32 */\r
155         shl     rax, cl\r
156         or      rdx, rax          ; /* hold |= *((uint *)in)++ << bits */\r
157 \r
158 L_get_distance_code:\r
159         and     r8, rdx           ; /* r8 &= hold */\r
160         mov     eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */\r
161 \r
162 L_dodist:\r
163         mov     r15d, eax         ; /* dist = this */\r
164         shr     r15d, 16           ; /* dist = this.val */\r
165         mov     cl, ah\r
166         sub     bl, ah            ; /* bits -= this.bits */\r
167         shr     rdx, cl           ; /* hold >>= this.bits */\r
168         mov     cl, al            ; /* cl = this.op */\r
169 \r
170         test    al, 16             ; /* if ((op & 16) == 0) */\r
171         jz      L_test_for_second_level_dist\r
172         and     cl, 15             ; /* op &= 15 */\r
173         jz      L_check_dist_one\r
174 \r
175 L_add_bits_to_dist:\r
176         sub     bl, cl\r
177         xor     eax, eax\r
178         inc     eax\r
179         shl     eax, cl\r
180         dec     eax                 ; /* (1 << op) - 1 */\r
181         and     eax, edx          ; /* eax &= hold */\r
182         shr     rdx, cl\r
183         add     r15d, eax         ; /* dist += hold & ((1 << op) - 1) */\r
184 \r
185 L_check_window:\r
186         mov     r8, rsi           ; /* save in so from can use it's reg */\r
187         mov     rax, rdi\r
188         sub     rax, [rsp+40]      ; /* nbytes = out - beg */\r
189 \r
190         cmp     eax, r15d\r
191         jb      L_clip_window        ; /* if (dist > nbytes) 4.2% */\r
192 \r
193         mov     ecx, r14d         ; /* ecx = len */\r
194         mov     rsi, rdi\r
195         sub     rsi, r15          ; /* from = out - dist */\r
196 \r
197         sar     ecx, 1\r
198         jnc     L_copy_two           ; /* if len % 2 == 0 */\r
199 \r
200         rep     movsw\r
201         mov     al, [rsi]\r
202         mov     [rdi], al\r
203         inc     rdi\r
204 \r
205         mov     rsi, r8           ; /* move in back to %rsi, toss from */\r
206         jmp     L_while_test\r
207 \r
208 L_copy_two:\r
209         rep     movsw\r
210         mov     rsi, r8           ; /* move in back to %rsi, toss from */\r
211         jmp     L_while_test\r
212 \r
213 ALIGN 4\r
214 L_check_dist_one:\r
215         cmp     r15d, 1            ; /* if dist 1, is a memset */\r
216         jne     L_check_window\r
217         cmp     [rsp+40], rdi      ; /* if out == beg, outside window */\r
218         je      L_check_window\r
219 \r
220         mov     ecx, r14d         ; /* ecx = len */\r
221         mov     al, [rdi-1]\r
222         mov     ah, al\r
223 \r
224         sar     ecx, 1\r
225         jnc     L_set_two\r
226         mov     [rdi], al\r
227         inc     rdi\r
228 \r
229 L_set_two:\r
230         rep     stosw\r
231         jmp     L_while_test\r
232 \r
233 ALIGN 4\r
234 L_test_for_second_level_length:\r
235         test    al, 64\r
236         jnz     L_test_for_end_of_block ; /* if ((op & 64) != 0) */\r
237 \r
238         xor     eax, eax\r
239         inc     eax\r
240         shl     eax, cl\r
241         dec     eax\r
242         and     eax, edx         ; /* eax &= hold */\r
243         add     eax, r14d        ; /* eax += len */\r
244         mov     eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/\r
245         jmp     L_dolen\r
246 \r
247 ALIGN 4\r
248 L_test_for_second_level_dist:\r
249         test    al, 64\r
250         jnz     L_invalid_distance_code ; /* if ((op & 64) != 0) */\r
251 \r
252         xor     eax, eax\r
253         inc     eax\r
254         shl     eax, cl\r
255         dec     eax\r
256         and     eax, edx         ; /* eax &= hold */\r
257         add     eax, r15d        ; /* eax += dist */\r
258         mov     eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/\r
259         jmp     L_dodist\r
260 \r
261 ALIGN 4\r
262 L_clip_window:\r
263         mov     ecx, eax         ; /* ecx = nbytes */\r
264         mov     eax, [rsp+92]     ; /* eax = wsize, prepare for dist cmp */\r
265         neg     ecx                ; /* nbytes = -nbytes */\r
266 \r
267         cmp     eax, r15d\r
268         jb      L_invalid_distance_too_far ; /* if (dist > wsize) */\r
269 \r
270         add     ecx, r15d         ; /* nbytes = dist - nbytes */\r
271         cmp     dword ptr [rsp+96], 0\r
272         jne     L_wrap_around_window ; /* if (write != 0) */\r
273 \r
274         mov     rsi, [rsp+56]     ; /* from  = window */\r
275         sub     eax, ecx         ; /* eax  -= nbytes */\r
276         add     rsi, rax         ; /* from += wsize - nbytes */\r
277 \r
278         mov     eax, r14d        ; /* eax = len */\r
279         cmp     r14d, ecx\r
280         jbe     L_do_copy           ; /* if (nbytes >= len) */\r
281 \r
282         sub     eax, ecx         ; /* eax -= nbytes */\r
283         rep     movsb\r
284         mov     rsi, rdi\r
285         sub     rsi, r15         ; /* from = &out[ -dist ] */\r
286         jmp     L_do_copy\r
287 \r
288 ALIGN 4\r
289 L_wrap_around_window:\r
290         mov     eax, [rsp+96]     ; /* eax = write */\r
291         cmp     ecx, eax\r
292         jbe     L_contiguous_in_window ; /* if (write >= nbytes) */\r
293 \r
294         mov     esi, [rsp+92]     ; /* from  = wsize */\r
295         add     rsi, [rsp+56]     ; /* from += window */\r
296         add     rsi, rax         ; /* from += write */\r
297         sub     rsi, rcx         ; /* from -= nbytes */\r
298         sub     ecx, eax         ; /* nbytes -= write */\r
299 \r
300         mov     eax, r14d        ; /* eax = len */\r
301         cmp     eax, ecx\r
302         jbe     L_do_copy           ; /* if (nbytes >= len) */\r
303 \r
304         sub     eax, ecx         ; /* len -= nbytes */\r
305         rep     movsb\r
306         mov     rsi, [rsp+56]     ; /* from = window */\r
307         mov     ecx, [rsp+96]     ; /* nbytes = write */\r
308         cmp     eax, ecx\r
309         jbe     L_do_copy           ; /* if (nbytes >= len) */\r
310 \r
311         sub     eax, ecx         ; /* len -= nbytes */\r
312         rep     movsb\r
313         mov     rsi, rdi\r
314         sub     rsi, r15         ; /* from = out - dist */\r
315         jmp     L_do_copy\r
316 \r
317 ALIGN 4\r
318 L_contiguous_in_window:\r
319         mov     rsi, [rsp+56]     ; /* rsi = window */\r
320         add     rsi, rax\r
321         sub     rsi, rcx         ; /* from += write - nbytes */\r
322 \r
323         mov     eax, r14d        ; /* eax = len */\r
324         cmp     eax, ecx\r
325         jbe     L_do_copy           ; /* if (nbytes >= len) */\r
326 \r
327         sub     eax, ecx         ; /* len -= nbytes */\r
328         rep     movsb\r
329         mov     rsi, rdi\r
330         sub     rsi, r15         ; /* from = out - dist */\r
331         jmp     L_do_copy           ; /* if (nbytes >= len) */\r
332 \r
333 ALIGN 4\r
334 L_do_copy:\r
335         mov     ecx, eax         ; /* ecx = len */\r
336         rep     movsb\r
337 \r
338         mov     rsi, r8          ; /* move in back to %esi, toss from */\r
339         jmp     L_while_test\r
340 \r
341 L_test_for_end_of_block:\r
342         test    al, 32\r
343         jz      L_invalid_literal_length_code\r
344         mov     dword ptr [rsp+116], 1\r
345         jmp     L_break_loop_with_status\r
346 \r
347 L_invalid_literal_length_code:\r
348         mov     dword ptr [rsp+116], 2\r
349         jmp     L_break_loop_with_status\r
350 \r
351 L_invalid_distance_code:\r
352         mov     dword ptr [rsp+116], 3\r
353         jmp     L_break_loop_with_status\r
354 \r
355 L_invalid_distance_too_far:\r
356         mov     dword ptr [rsp+116], 4\r
357         jmp     L_break_loop_with_status\r
358 \r
359 L_break_loop:\r
360         mov     dword ptr [rsp+116], 0\r
361 \r
362 L_break_loop_with_status:\r
363 ; /* put in, out, bits, and hold back into ar and pop esp */\r
364         mov     [rsp+16], rsi     ; /* in */\r
365         mov     [rsp+32], rdi     ; /* out */\r
366         mov     [rsp+88], ebx     ; /* bits */\r
367         mov     [rsp+80], rdx     ; /* hold */\r
368 \r
369         mov     rax, [rsp]       ; /* restore rbp and rsp */\r
370         mov     rbp, [rsp+8]\r
371         mov     rsp, rax\r
372 \r
373 \r
374 \r
375         mov rsi,[rsp-8]\r
376         mov rdi,[rsp-16]\r
377         mov r12,[rsp-24]\r
378         mov r13,[rsp-32]\r
379         mov r14,[rsp-40]\r
380         mov r15,[rsp-48]\r
381         mov rbx,[rsp-56]\r
382         \r
383     ret 0\r
384 ;          :\r
385 ;          : "m" (ar)\r
386 ;          : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi",\r
387 ;            "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"\r
388 ;    );\r
389 \r
390 inffas8664fnc   ENDP\r
391 ;_TEXT  ENDS\r
392 END\r