]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libz/contrib/asm686/match.S
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libz / contrib / asm686 / match.S
1 /* match.S -- x86 assembly version of the zlib longest_match() function.
2  * Optimized for the Intel 686 chips (PPro and later).
3  *
4  * Copyright (C) 1998, 2007 Brian Raiter <breadbox@muppetlabs.com>
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty.  In no event will the author be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 3. This notice may not be removed or altered from any source distribution.
21  */
22
23 #ifndef NO_UNDERLINE
24 #define match_init      _match_init
25 #define longest_match   _longest_match
26 #endif
27
28 #define MAX_MATCH       (258)
29 #define MIN_MATCH       (3)
30 #define MIN_LOOKAHEAD   (MAX_MATCH + MIN_MATCH + 1)
31 #define MAX_MATCH_8     ((MAX_MATCH + 7) & ~7)
32
33 /* stack frame offsets */
34
35 #define chainlenwmask           0       /* high word: current chain len */
36                                         /* low word: s->wmask           */
37 #define window                  4       /* local copy of s->window      */
38 #define windowbestlen           8       /* s->window + bestlen          */
39 #define scanstart               16      /* first two bytes of string    */
40 #define scanend                 12      /* last two bytes of string     */
41 #define scanalign               20      /* dword-misalignment of string */
42 #define nicematch               24      /* a good enough match size     */
43 #define bestlen                 28      /* size of best match so far    */
44 #define scan                    32      /* ptr to string wanting match  */
45
46 #define LocalVarsSize           (36)
47 /*      saved ebx               36 */
48 /*      saved edi               40 */
49 /*      saved esi               44 */
50 /*      saved ebp               48 */
51 /*      return address          52 */
52 #define deflatestate            56      /* the function arguments       */
53 #define curmatch                60
54
55 /* All the +zlib1222add offsets are due to the addition of fields
56  *  in zlib in the deflate_state structure since the asm code was first written
57  * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
58  * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
59  * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
60  */
61
62 #define zlib1222add             (8)
63
64 #define dsWSize                 (36+zlib1222add)
65 #define dsWMask                 (44+zlib1222add)
66 #define dsWindow                (48+zlib1222add)
67 #define dsPrev                  (56+zlib1222add)
68 #define dsMatchLen              (88+zlib1222add)
69 #define dsPrevMatch             (92+zlib1222add)
70 #define dsStrStart              (100+zlib1222add)
71 #define dsMatchStart            (104+zlib1222add)
72 #define dsLookahead             (108+zlib1222add)
73 #define dsPrevLen               (112+zlib1222add)
74 #define dsMaxChainLen           (116+zlib1222add)
75 #define dsGoodMatch             (132+zlib1222add)
76 #define dsNiceMatch             (136+zlib1222add)
77
78
79 .file "match.S"
80
81 .globl  match_init, longest_match
82
83 .text
84
85 /* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
86
87 longest_match:
88
89 /* Save registers that the compiler may be using, and adjust %esp to    */
90 /* make room for our stack frame.                                       */
91
92                 pushl   %ebp
93                 pushl   %edi
94                 pushl   %esi
95                 pushl   %ebx
96                 subl    $LocalVarsSize, %esp
97
98 /* Retrieve the function arguments. %ecx will hold cur_match            */
99 /* throughout the entire function. %edx will hold the pointer to the    */
100 /* deflate_state structure during the function's setup (before          */
101 /* entering the main loop).                                             */
102
103                 movl    deflatestate(%esp), %edx
104                 movl    curmatch(%esp), %ecx
105
106 /* uInt wmask = s->w_mask;                                              */
107 /* unsigned chain_length = s->max_chain_length;                         */
108 /* if (s->prev_length >= s->good_match) {                               */
109 /*     chain_length >>= 2;                                              */
110 /* }                                                                    */
111
112                 movl    dsPrevLen(%edx), %eax
113                 movl    dsGoodMatch(%edx), %ebx
114                 cmpl    %ebx, %eax
115                 movl    dsWMask(%edx), %eax
116                 movl    dsMaxChainLen(%edx), %ebx
117                 jl      LastMatchGood
118                 shrl    $2, %ebx
119 LastMatchGood:
120
121 /* chainlen is decremented once beforehand so that the function can     */
122 /* use the sign flag instead of the zero flag for the exit test.        */
123 /* It is then shifted into the high word, to make room for the wmask    */
124 /* value, which it will always accompany.                               */
125
126                 decl    %ebx
127                 shll    $16, %ebx
128                 orl     %eax, %ebx
129                 movl    %ebx, chainlenwmask(%esp)
130
131 /* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;      */
132
133                 movl    dsNiceMatch(%edx), %eax
134                 movl    dsLookahead(%edx), %ebx
135                 cmpl    %eax, %ebx
136                 jl      LookaheadLess
137                 movl    %eax, %ebx
138 LookaheadLess:  movl    %ebx, nicematch(%esp)
139
140 /* register Bytef *scan = s->window + s->strstart;                      */
141
142                 movl    dsWindow(%edx), %esi
143                 movl    %esi, window(%esp)
144                 movl    dsStrStart(%edx), %ebp
145                 lea     (%esi,%ebp), %edi
146                 movl    %edi, scan(%esp)
147
148 /* Determine how many bytes the scan ptr is off from being              */
149 /* dword-aligned.                                                       */
150
151                 movl    %edi, %eax
152                 negl    %eax
153                 andl    $3, %eax
154                 movl    %eax, scanalign(%esp)
155
156 /* IPos limit = s->strstart > (IPos)MAX_DIST(s) ?                       */
157 /*     s->strstart - (IPos)MAX_DIST(s) : NIL;                           */
158
159                 movl    dsWSize(%edx), %eax
160                 subl    $MIN_LOOKAHEAD, %eax
161                 subl    %eax, %ebp
162                 jg      LimitPositive
163                 xorl    %ebp, %ebp
164 LimitPositive:
165
166 /* int best_len = s->prev_length;                                       */
167
168                 movl    dsPrevLen(%edx), %eax
169                 movl    %eax, bestlen(%esp)
170
171 /* Store the sum of s->window + best_len in %esi locally, and in %esi.  */
172
173                 addl    %eax, %esi
174                 movl    %esi, windowbestlen(%esp)
175
176 /* register ush scan_start = *(ushf*)scan;                              */
177 /* register ush scan_end   = *(ushf*)(scan+best_len-1);                 */
178 /* Posf *prev = s->prev;                                                */
179
180                 movzwl  (%edi), %ebx
181                 movl    %ebx, scanstart(%esp)
182                 movzwl  -1(%edi,%eax), %ebx
183                 movl    %ebx, scanend(%esp)
184                 movl    dsPrev(%edx), %edi
185
186 /* Jump into the main loop.                                             */
187
188                 movl    chainlenwmask(%esp), %edx
189                 jmp     LoopEntry
190
191 .balign 16
192
193 /* do {
194  *     match = s->window + cur_match;
195  *     if (*(ushf*)(match+best_len-1) != scan_end ||
196  *         *(ushf*)match != scan_start) continue;
197  *     [...]
198  * } while ((cur_match = prev[cur_match & wmask]) > limit
199  *          && --chain_length != 0);
200  *
201  * Here is the inner loop of the function. The function will spend the
202  * majority of its time in this loop, and majority of that time will
203  * be spent in the first ten instructions.
204  *
205  * Within this loop:
206  * %ebx = scanend
207  * %ecx = curmatch
208  * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
209  * %esi = windowbestlen - i.e., (window + bestlen)
210  * %edi = prev
211  * %ebp = limit
212  */
213 LookupLoop:
214                 andl    %edx, %ecx
215                 movzwl  (%edi,%ecx,2), %ecx
216                 cmpl    %ebp, %ecx
217                 jbe     LeaveNow
218                 subl    $0x00010000, %edx
219                 js      LeaveNow
220 LoopEntry:      movzwl  -1(%esi,%ecx), %eax
221                 cmpl    %ebx, %eax
222                 jnz     LookupLoop
223                 movl    window(%esp), %eax
224                 movzwl  (%eax,%ecx), %eax
225                 cmpl    scanstart(%esp), %eax
226                 jnz     LookupLoop
227
228 /* Store the current value of chainlen.                                 */
229
230                 movl    %edx, chainlenwmask(%esp)
231
232 /* Point %edi to the string under scrutiny, and %esi to the string we   */
233 /* are hoping to match it up with. In actuality, %esi and %edi are      */
234 /* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is      */
235 /* initialized to -(MAX_MATCH_8 - scanalign).                           */
236
237                 movl    window(%esp), %esi
238                 movl    scan(%esp), %edi
239                 addl    %ecx, %esi
240                 movl    scanalign(%esp), %eax
241                 movl    $(-MAX_MATCH_8), %edx
242                 lea     MAX_MATCH_8(%edi,%eax), %edi
243                 lea     MAX_MATCH_8(%esi,%eax), %esi
244
245 /* Test the strings for equality, 8 bytes at a time. At the end,
246  * adjust %edx so that it is offset to the exact byte that mismatched.
247  *
248  * We already know at this point that the first three bytes of the
249  * strings match each other, and they can be safely passed over before
250  * starting the compare loop. So what this code does is skip over 0-3
251  * bytes, as much as necessary in order to dword-align the %edi
252  * pointer. (%esi will still be misaligned three times out of four.)
253  *
254  * It should be confessed that this loop usually does not represent
255  * much of the total running time. Replacing it with a more
256  * straightforward "rep cmpsb" would not drastically degrade
257  * performance.
258  */
259 LoopCmps:
260                 movl    (%esi,%edx), %eax
261                 xorl    (%edi,%edx), %eax
262                 jnz     LeaveLoopCmps
263                 movl    4(%esi,%edx), %eax
264                 xorl    4(%edi,%edx), %eax
265                 jnz     LeaveLoopCmps4
266                 addl    $8, %edx
267                 jnz     LoopCmps
268                 jmp     LenMaximum
269 LeaveLoopCmps4: addl    $4, %edx
270 LeaveLoopCmps:  testl   $0x0000FFFF, %eax
271                 jnz     LenLower
272                 addl    $2, %edx
273                 shrl    $16, %eax
274 LenLower:       subb    $1, %al
275                 adcl    $0, %edx
276
277 /* Calculate the length of the match. If it is longer than MAX_MATCH,   */
278 /* then automatically accept it as the best possible match and leave.   */
279
280                 lea     (%edi,%edx), %eax
281                 movl    scan(%esp), %edi
282                 subl    %edi, %eax
283                 cmpl    $MAX_MATCH, %eax
284                 jge     LenMaximum
285
286 /* If the length of the match is not longer than the best match we      */
287 /* have so far, then forget it and return to the lookup loop.           */
288
289                 movl    deflatestate(%esp), %edx
290                 movl    bestlen(%esp), %ebx
291                 cmpl    %ebx, %eax
292                 jg      LongerMatch
293                 movl    windowbestlen(%esp), %esi
294                 movl    dsPrev(%edx), %edi
295                 movl    scanend(%esp), %ebx
296                 movl    chainlenwmask(%esp), %edx
297                 jmp     LookupLoop
298
299 /*         s->match_start = cur_match;                                  */
300 /*         best_len = len;                                              */
301 /*         if (len >= nice_match) break;                                */
302 /*         scan_end = *(ushf*)(scan+best_len-1);                        */
303
304 LongerMatch:    movl    nicematch(%esp), %ebx
305                 movl    %eax, bestlen(%esp)
306                 movl    %ecx, dsMatchStart(%edx)
307                 cmpl    %ebx, %eax
308                 jge     LeaveNow
309                 movl    window(%esp), %esi
310                 addl    %eax, %esi
311                 movl    %esi, windowbestlen(%esp)
312                 movzwl  -1(%edi,%eax), %ebx
313                 movl    dsPrev(%edx), %edi
314                 movl    %ebx, scanend(%esp)
315                 movl    chainlenwmask(%esp), %edx
316                 jmp     LookupLoop
317
318 /* Accept the current string, with the maximum possible length.         */
319
320 LenMaximum:     movl    deflatestate(%esp), %edx
321                 movl    $MAX_MATCH, bestlen(%esp)
322                 movl    %ecx, dsMatchStart(%edx)
323
324 /* if ((uInt)best_len <= s->lookahead) return (uInt)best_len;           */
325 /* return s->lookahead;                                                 */
326
327 LeaveNow:
328                 movl    deflatestate(%esp), %edx
329                 movl    bestlen(%esp), %ebx
330                 movl    dsLookahead(%edx), %eax
331                 cmpl    %eax, %ebx
332                 jg      LookaheadRet
333                 movl    %ebx, %eax
334 LookaheadRet:
335
336 /* Restore the stack and return from whence we came.                    */
337
338                 addl    $LocalVarsSize, %esp
339                 popl    %ebx
340                 popl    %esi
341                 popl    %edi
342                 popl    %ebp
343 match_init:     ret