Imported Upstream version 1.5
[debian/gzip] / lib / match.c
1 /* match.s -- optional optimized asm version of longest match in deflate.c
2
3    Copyright (C) 2002, 2006, 2009-2012 Free Software Foundation, Inc.
4    Copyright (C) 1992-1993 Jean-loup Gailly
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19
20 /*
21  * The 68020 version has been written by Francesco Potorti` <pot@cnuce.cnr.it>
22  * with adaptations by Carsten Steger <stegerc@informatik.tu-muenchen.de>,
23  * Andreas Schwab <schwab@lamothe.informatik.uni-dortmund.de> and
24  * Kristoffer Eriksson <ske@pkmab.se>
25  *
26  * The ia64 version has been written by Sverre Jarp (HP Labs) 2001-2002.
27  * Unwind directives and some reformatting for better readability added by
28  * David Mosberger-Tang <davidm@hpl.hp.com>.
29  */
30
31 /* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
32  * external symbols with an underline character '_'.
33  */
34 #ifdef NO_UNDERLINE
35 #  define _prev             prev
36 #  define _window           window
37 #  define _match_start      match_start
38 #  define _prev_length      prev_length
39 #  define _good_match       good_match
40 #  define _nice_match       nice_match
41 #  define _strstart         strstart
42 #  define _max_chain_length max_chain_length
43
44 #  define _match_init       match_init
45 #  define _longest_match    longest_match
46 #endif
47
48 #ifdef DYN_ALLOC
49   error: DYN_ALLOC not yet supported in match.s
50 #endif
51
52 #if defined(i386) || defined(_I386) || defined(__i386) || defined(__i386__)
53
54 /* This version is for 386 Unix or OS/2 in 32 bit mode.
55  * Warning: it uses the AT&T syntax: mov source,dest
56  * This file is only optional. If you want to force the C version,
57  * add -DNO_ASM to CFLAGS in Makefile and set OBJA to an empty string.
58  * If you have reduced WSIZE in gzip.h, then change its value below.
59  * This version assumes static allocation of the arrays (-DDYN_ALLOC not used).
60  */
61
62         .file   "match.S"
63
64 #define MAX_MATCH       258
65 #define MAX_MATCH2      $128 /* MAX_MATCH/2-1 */
66 #define MIN_MATCH       3
67 #define    WSIZE        $32768
68 #define MAX_DIST        WSIZE - MAX_MATCH - MIN_MATCH - 1
69
70         .globl  _match_init
71         .globl  _longest_match
72
73         .text
74
75 _match_init:
76         ret
77
78 /*-----------------------------------------------------------------------
79  * Set match_start to the longest match starting at the given string and
80  * return its length. Matches shorter or equal to prev_length are discarded,
81  * in which case the result is equal to prev_length and match_start is
82  * garbage.
83  * IN assertions: cur_match is the head of the hash chain for the current
84  *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
85  */
86
87 _longest_match: /* int longest_match(cur_match) */
88
89 #define cur_match   20(%esp)
90      /* return address */               /* esp+16 */
91         push    %ebp                    /* esp+12 */
92         push    %edi                    /* esp+8  */
93         push    %esi                    /* esp+4  */
94         push    %ebx                    /* esp    */
95
96 /*
97  *      match        equ esi
98  *      scan         equ edi
99  *      chain_length equ ebp
100  *      best_len     equ ebx
101  *      limit        equ edx
102  */
103         mov     cur_match,%esi
104         mov     _max_chain_length,%ebp /* chain_length = max_chain_length */
105         mov     _strstart,%edi
106         mov     %edi,%edx
107         sub     MAX_DIST,%edx          /* limit = strstart-MAX_DIST */
108         jae     limit_ok
109         sub     %edx,%edx              /* limit = NIL */
110 limit_ok:
111         add     $2+_window,%edi        /* edi = offset(window+strstart+2) */
112         mov     _prev_length,%ebx      /* best_len = prev_length */
113         movw    -3(%ebx,%edi),%ax      /* ax = scan[best_len-1..best_len] */
114         movw    -2(%edi),%cx           /* cx = scan[0..1] */
115         cmp     _good_match,%ebx       /* do we have a good match already? */
116         jb      do_scan
117         shr     $2,%ebp                /* chain_length >>= 2 */
118         jmp     do_scan
119
120         .align  4
121 long_loop:
122 /* at this point, edi == scan+2, esi == cur_match */
123         movw    -3(%ebx,%edi),%ax       /* ax = scan[best_len-1..best_len] */
124         movw     -2(%edi),%cx           /* cx = scan[0..1] */
125 short_loop:
126 /*
127  * at this point, di == scan+2, si == cur_match,
128  * ax = scan[best_len-1..best_len] and cx = scan[0..1]
129  */
130         and     WSIZE-1, %esi
131         movw    _prev(%esi,%esi),%si    /* cur_match = prev[cur_match] */
132                                         /* top word of esi is still 0 */
133         cmp     %edx,%esi               /* cur_match <= limit ? */
134         jbe     the_end
135         dec     %ebp                    /* --chain_length */
136         jz      the_end
137 do_scan:
138         cmpw    _window-1(%ebx,%esi),%ax/* check match at best_len-1 */
139         jne     short_loop
140         cmpw    _window(%esi),%cx       /* check min_match_length match */
141         jne     short_loop
142
143         lea     _window+2(%esi),%esi    /* si = match */
144         mov     %edi,%eax               /* ax = scan+2 */
145         mov     MAX_MATCH2,%ecx         /* scan for at most MAX_MATCH bytes */
146         rep;    cmpsw                   /* loop until mismatch */
147         je      maxmatch                /* match of length MAX_MATCH? */
148 mismatch:
149         movb    -2(%edi),%cl        /* mismatch on first or second byte? */
150         subb    -2(%esi),%cl        /* cl = 0 if first bytes equal */
151         xchg    %edi,%eax           /* edi = scan+2, eax = end of scan */
152         sub     %edi,%eax           /* eax = len */
153         sub     %eax,%esi           /* esi = cur_match + 2 + offset(window) */
154         sub     $2+_window,%esi     /* esi = cur_match */
155         subb    $1,%cl              /* set carry if cl == 0 (cannot use DEC) */
156         adc     $0,%eax             /* eax = carry ? len+1 : len */
157         cmp     %ebx,%eax           /* len > best_len ? */
158         jle     long_loop
159         mov     %esi,_match_start       /* match_start = cur_match */
160         mov     %eax,%ebx               /* ebx = best_len = len */
161         cmp     _nice_match,%eax        /* len >= nice_match ? */
162         jl      long_loop
163 the_end:
164         mov     %ebx,%eax               /* result = eax = best_len */
165         pop     %ebx
166         pop     %esi
167         pop     %edi
168         pop     %ebp
169         ret
170 maxmatch:
171         cmpsb
172         jmp     mismatch
173
174 #else
175
176 /* ======================== 680x0 version ================================= */
177
178 #if defined(m68k)||defined(mc68k)||defined(__mc68000__)||defined(__MC68000__)
179 #  ifndef mc68000
180 #    define mc68000
181 #  endif
182 #endif
183
184 #if defined(__mc68020__) || defined(__MC68020__) || defined(sysV68)
185 #  ifndef mc68020
186 #    define mc68020
187 #  endif
188 #endif
189
190 #if defined(mc68020) || defined(mc68000)
191
192 #if (defined(mc68020) || defined(NeXT)) && !defined(UNALIGNED_OK)
193 #  define UNALIGNED_OK
194 #endif
195
196 #ifdef sysV68  /* Try Motorola Delta style */
197
198 #  define GLOBAL(symbol)        global  symbol
199 #  define TEXT                  text
200 #  define FILE(filename)        file    filename
201 #  define invert_maybe(src,dst) dst,src
202 #  define imm(data)             &data
203 #  define reg(register)         %register
204
205 #  define addl                  add.l
206 #  define addql                 addq.l
207 #  define blos                  blo.b
208 #  define bhis                  bhi.b
209 #  define bras                  bra.b
210 #  define clrl                  clr.l
211 #  define cmpmb                 cmpm.b
212 #  define cmpw                  cmp.w
213 #  define cmpl                  cmp.l
214 #  define lslw                  lsl.w
215 #  define lsrl                  lsr.l
216 #  define movel                 move.l
217 #  define movew                 move.w
218 #  define moveb                 move.b
219 #  define moveml                movem.l
220 #  define subl                  sub.l
221 #  define subw                  sub.w
222 #  define subql                 subq.l
223
224 #  define IndBase(bd,An)        (bd,An)
225 #  define IndBaseNdxl(bd,An,Xn) (bd,An,Xn.l)
226 #  define IndBaseNdxw(bd,An,Xn) (bd,An,Xn.w)
227 #  define predec(An)            -(An)
228 #  define postinc(An)           (An)+
229
230 #else /* default style (Sun 3, NeXT, Amiga, Atari) */
231
232 #  define GLOBAL(symbol)        .globl  symbol
233 #  define TEXT                  .text
234 #  define FILE(filename)        .even
235 #  define invert_maybe(src,dst) src,dst
236 #  if defined(sun) || defined(mc68k)
237 #    define imm(data)           #data
238 #  else
239 #    define imm(data)           \#data
240 #  endif
241 #  define reg(register)         register
242
243 #  define blos                  bcss
244 #  if defined(sun) || defined(mc68k)
245 #    define movel               movl
246 #    define movew               movw
247 #    define moveb               movb
248 #  endif
249 #  define IndBase(bd,An)        An@(bd)
250 #  define IndBaseNdxl(bd,An,Xn) An@(bd,Xn:l)
251 #  define IndBaseNdxw(bd,An,Xn) An@(bd,Xn:w)
252 #  define predec(An)            An@-
253 #  define postinc(An)           An@+
254
255 #endif  /* styles */
256
257 #define Best_Len        reg(d0)         /* unsigned */
258 #define Cur_Match       reg(d1)         /* Ipos */
259 #define Loop_Counter    reg(d2)         /* int */
260 #define Scan_Start      reg(d3)         /* unsigned short */
261 #define Scan_End        reg(d4)         /* unsigned short */
262 #define Limit           reg(d5)         /* IPos */
263 #define Chain_Length    reg(d6)         /* unsigned */
264 #define Scan_Test       reg(d7)
265 #define Scan            reg(a0)         /* *uch */
266 #define Match           reg(a1)         /* *uch */
267 #define Prev_Address    reg(a2)         /* *Pos */
268 #define Scan_Ini        reg(a3)         /* *uch */
269 #define Match_Ini       reg(a4)         /* *uch */
270 #define Stack_Pointer   reg(sp)
271
272 #define MAX_MATCH       258
273 #define MIN_MATCH       3
274 #define WSIZE           32768
275 #define MAX_DIST        (WSIZE - MAX_MATCH - MIN_MATCH - 1)
276
277         GLOBAL  (_match_init)
278         GLOBAL  (_longest_match)
279
280         TEXT
281
282         FILE    ("match.S")
283
284 _match_init:
285         rts
286
287 /*-----------------------------------------------------------------------
288  * Set match_start to the longest match starting at the given string and
289  * return its length. Matches shorter or equal to prev_length are discarded,
290  * in which case the result is equal to prev_length and match_start is
291  * garbage.
292  * IN assertions: cur_match is the head of the hash chain for the current
293  *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
294  */
295
296 /* int longest_match (cur_match) */
297
298 #ifdef UNALIGNED_OK
299 #  define pushreg       15928           /* d2-d6/a2-a4 */
300 #  define popreg        7292
301 #else
302 #  define pushreg       16184           /* d2-d7/a2-a4 */
303 #  define popreg        7420
304 #endif
305
306 _longest_match:
307         movel   IndBase(4,Stack_Pointer),Cur_Match
308         moveml  imm(pushreg),predec(Stack_Pointer)
309         movel   _max_chain_length,Chain_Length
310         movel   _prev_length,Best_Len
311         movel   imm(_prev),Prev_Address
312         movel   imm(_window+MIN_MATCH),Match_Ini
313         movel   _strstart,Limit
314         movel   Match_Ini,Scan_Ini
315         addl    Limit,Scan_Ini
316         subw    imm(MAX_DIST),Limit
317         bhis    L__limit_ok
318         clrl    Limit
319 L__limit_ok:
320         cmpl    invert_maybe(_good_match,Best_Len)
321         blos    L__length_ok
322         lsrl    imm(2),Chain_Length
323 L__length_ok:
324         subql   imm(1),Chain_Length
325 #ifdef UNALIGNED_OK
326         movew   IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
327         movew   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
328 #else
329         moveb   IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
330         lslw    imm(8),Scan_Start
331         moveb   IndBase(-MIN_MATCH+1,Scan_Ini),Scan_Start
332         moveb   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
333         lslw    imm(8),Scan_End
334         moveb   IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
335 #endif
336         bras    L__do_scan
337
338 L__long_loop:
339 #ifdef UNALIGNED_OK
340         movew   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
341 #else
342         moveb   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
343         lslw    imm(8),Scan_End
344         moveb   IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
345 #endif
346
347 L__short_loop:
348         lslw    imm(1),Cur_Match
349         movew   IndBaseNdxl(0,Prev_Address,Cur_Match),Cur_Match
350         cmpw    invert_maybe(Limit,Cur_Match)
351         dbls    Chain_Length,L__do_scan
352         bras    L__return
353
354 L__do_scan:
355         movel   Match_Ini,Match
356         addl    Cur_Match,Match
357 #ifdef UNALIGNED_OK
358         cmpw    invert_maybe(IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_End)
359         bne     L__short_loop
360         cmpw    invert_maybe(IndBase(-MIN_MATCH,Match),Scan_Start)
361         bne     L__short_loop
362 #else
363         moveb   IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_Test
364         lslw    imm(8),Scan_Test
365         moveb   IndBaseNdxw(-MIN_MATCH,Match,Best_Len),Scan_Test
366         cmpw    invert_maybe(Scan_Test,Scan_End)
367         bne     L__short_loop
368         moveb   IndBase(-MIN_MATCH,Match),Scan_Test
369         lslw    imm(8),Scan_Test
370         moveb   IndBase(-MIN_MATCH+1,Match),Scan_Test
371         cmpw    invert_maybe(Scan_Test,Scan_Start)
372         bne     L__short_loop
373 #endif
374
375         movew   imm((MAX_MATCH-MIN_MATCH+1)-1),Loop_Counter
376         movel   Scan_Ini,Scan
377 L__scan_loop:
378         cmpmb   postinc(Match),postinc(Scan)
379         dbne    Loop_Counter,L__scan_loop
380
381         subl    Scan_Ini,Scan
382         addql   imm(MIN_MATCH-1),Scan
383         cmpl    invert_maybe(Best_Len,Scan)
384         bls     L__short_loop
385         movel   Scan,Best_Len
386         movel   Cur_Match,_match_start
387         cmpl    invert_maybe(_nice_match,Best_Len)
388         blos    L__long_loop
389 L__return:
390         moveml  postinc(Stack_Pointer),imm(popreg)
391         rts
392
393 #else
394
395 # if defined (__ia64__)
396
397 /* ======================== ia64 version ================================= */
398
399 /*
400  * 'longest_match.S' (assembly program for gzip for the IA-64 architecture)
401  *
402  * Optimised for McKinley, but with Merced-compatibility, such as MIB+MIB, used wherever
403  * possible.
404  *
405  * Copyright: Sverre Jarp (HP Labs) 2001-2002
406  *
407  * See deflate.c for c-version
408  * Version 2 - Optimize the outer loop
409  */
410
411 #include <endian.h>
412
413 #if __BYTE_ORDER == ____BIG_ENDIAN
414 #define  first  shl
415 #define  second shr.u
416 #define  count  czx1.l
417 #else
418 #define  first  shr.u
419 #define  second shl
420 #define  count  czx1.r
421 #endif
422
423 // 24 rotating register (r32 - r55)
424
425 #define s_vmatch0               r32
426 #define s_vmatch1               r33
427 #define s_vmatbst               r34
428 #define s_vmatbst1              r35
429 #define s_amatblen              r36
430
431 #define s_tm1                   r56
432 #define s_tm2                   r57
433 #define s_tm3                   r58
434 #define s_tm4                   r59
435 #define s_tm5                   r60
436 #define s_tm6                   r61
437 #define s_tm7                   r62
438 #define s_tm8                   r63
439
440 #define s_vlen                  r31
441 #define s_vstrstart             r30
442 #define s_vchainlen             r29
443 #define s_awinbest              r28
444 #define s_vcurmatch             r27
445 #define s_vlimit                r26
446 #define s_vscanend              r25
447 #define s_vscanend1             r24
448 #define s_anicematch            r23
449 #define s_vscan0                r22
450 #define s_vscan1                r21
451
452 #define s_aprev                 r20
453 #define s_awindow               r19
454 #define s_amatchstart           r18
455 #define s_ascan                 r17
456 #define s_amatch                r16
457 #define s_wmask                 r15
458 #define s_ascanend              r14
459
460 #define s_vspec_cmatch          r11             // next iteration
461 #define s_lcsave                r10
462 #define s_prsave                r9
463 #define s_vbestlen              r8              // return register
464
465 #define s_vscan3                r3
466 #define s_vmatch3               r2
467
468 #define p_no                    p2
469 #define p_yes                   p3
470 #define p_shf                   p4              //
471 #define p_bn2                   p5              // Use in loop (indicating bestlen != 2)
472
473 #define p_nbs                   p9              // not new best_len
474 #define p_nnc                   p10             // not nice_length
475 #define p_ll                    p11
476 #define p_end                   p12
477
478 #define MAX_MATCH               258
479 #define MIN_MATCH                 4
480 #define WSIZE                 32768
481 #define MAX_DIST                WSIZE - MAX_MATCH - MIN_MATCH - 1
482
483 #define R_INPUT                 1
484 #define R_LOCAL                 31
485 #define R_OUTPUT                0
486 #define R_ROTATING              24
487 #define MLAT                    3
488 #define SHLAT                   2
489
490 #define mova                    mov
491 #define movi0                   mov
492 #define cgtu                    cmp.gt.unc
493 #define cgeu                    cmp.ge.unc
494 #define cneu                    cmp.ne.unc
495
496         .global longest_match
497         .proc longest_match
498         .align 32
499 longest_match:
500 // --  Cycle: 0
501         .prologue
502 {.mmi
503          alloc r2=ar.pfs,R_INPUT,R_LOCAL,R_OUTPUT,R_ROTATING
504         .rotr scan[MLAT+2], match[MLAT+2], shscan0[SHLAT+1], \
505               shscan1[SHLAT+1], shmatch0[SHLAT+1], shmatch1[SHLAT+1]
506         .rotp lc[MLAT+SHLAT+2]
507         mova s_vspec_cmatch=in0 // cur_match from input register
508         add s_tm1=@gprel(strstart),gp // a(a(strstart))
509 }{.mmi
510         add s_tm3=@gprel(prev_length),gp // a(a(prev_length))
511         add s_tm5=@ltoff(window),gp // a(a(window))
512         add s_tm6=@ltoff(prev),gp // a(a(prev))
513         ;;
514 }{.mmb  //  Cycle: 1
515         ld4 s_vstrstart=[s_tm1] // strstart
516         ld4 s_vbestlen=[s_tm3] // best_len = prev_length
517         brp.loop.imp .cmploop,.cmploop+48
518 }{.mli
519         add s_tm2=@gprel(max_chain_length),gp // a(a(max_chain_length))
520         movl s_wmask=WSIZE-1
521         ;;
522 }{.mmi  //  Cycle: 2
523         ld8 s_aprev=[s_tm6] // a(prev)
524         ld8 s_awindow=[s_tm5] // a(window)
525         .save pr, s_prsave
526         movi0 s_prsave=pr // save predicates
527 }{.mmi
528         add s_tm4=@gprel(good_match),gp // a(a(good_match))
529         add s_tm7=@ltoff(nice_match),gp // a(a(nice_match))
530         add s_tm8=@ltoff(match_start),gp // a(match_start)
531         ;;
532 }{.mmi  //  Cycle: 3
533         ld8 s_anicematch=[s_tm7] // a(nice_match)
534         ld8 s_amatchstart=[s_tm8] // a(match_start)
535         .save ar.lc, s_lcsave
536         movi0 s_lcsave=ar.lc // save loop count register
537 }{.mmi
538         .body
539         add s_tm1=-(MAX_MATCH + MIN_MATCH),s_wmask // maxdist
540         cmp.eq p_ll,p0=r0,r0 // parallel compare initialized as 'true'
541         mova s_vcurmatch=s_vspec_cmatch
542         ;;
543 }{.mmi  //  Cycle: 4
544         ld4 s_vchainlen=[s_tm2] // chain_length=max_chain_length
545         ld4 s_tm4=[s_tm4] // v(good_match)
546         add s_ascan=s_awindow,s_vstrstart // scan=window + strstart
547 }{.mmi
548         sub s_vlimit=s_vstrstart, s_tm1 // limit=strstart - MAX_DIST
549         add s_amatch=s_awindow,s_vspec_cmatch // match=window + cur_match
550         and s_vspec_cmatch =s_vspec_cmatch,s_wmask
551         ;;
552 }{.mmi  //  Cycle: 5
553         add s_amatblen=s_amatch,s_vbestlen //
554         cneu p_bn2,p0=2,s_vbestlen // set if bestlen != 2
555         add s_ascanend=s_ascan,s_vbestlen // compute a(scan) + best_len
556 }{.mmi
557         ld1 s_vscan0=[s_ascan],1 // NB: s_ascan++
558         ld1 s_vmatch0=[s_amatch],1
559         cgtu p0,p_no=s_vlimit,r0 // is result positive ?
560         ;;
561 }{.mmi  //  Cycle: 6
562         ld1.nt1 s_vscan1=[s_ascan],2 // NB: s_ascan+3 in total
563         ld1.nt1 s_vmatch1=[s_amatch],2
564         add s_awinbest=s_awindow,s_vbestlen //
565         ;;
566 }{.mmi  //  Cycle: 7
567         ld1.nt1 s_vscanend=[s_ascanend],-1 // scan_end=scan[best_len]
568         ld1.nt1 s_vmatbst=[s_amatblen],-1
569 (p_no)  mova s_vlimit=r0
570         ;;
571 }{.mmi  //  Cycle: 8
572 (p_bn2) ld1.nt1 s_vscanend1=[s_ascanend],1 // scan_end1=scan[best_len-1]
573 (p_bn2) ld1.nt1 s_vmatbst1=[s_amatblen]
574         shladd s_vspec_cmatch =s_vspec_cmatch,1,s_aprev
575 }{.mmi
576         cgeu p_shf,p0=s_vbestlen,s_tm4 // is (prev_length >= good_match) ?
577         ;;
578 }{.mmi  //  Cycle: 9
579         ld1.nt1 s_vscan3=[s_ascan]
580         ld2.nt1 s_vspec_cmatch=[s_vspec_cmatch]
581         mova    s_vlen=3
582 }{.mmi
583 (p_shf) shr.u s_vchainlen=s_vchainlen,2 // (cur_len) >> 2
584         ;;
585 }{.mmi  //  Cycle: 10
586         ld1.nt1 s_vmatch3=[s_amatch]
587         // p_ll switched on as soon as we get a mismatch:
588         cmp.eq.and p_ll,p0=s_vmatch0,s_vscan0
589         cmp.eq.and p_ll,p0=s_vmatbst,s_vscanend
590 }{.mib
591         cmp.eq.and p_ll,p0=s_vmatch1,s_vscan1
592 (p_bn2) cmp.eq.and p_ll,p0=s_vmatbst1,s_vscanend1
593 (p_ll)  br.cond.dpnt.many .test_more
594         ;;
595 }
596
597 .next_iter:
598 {.mmi   // Cycle 0
599         add s_amatch=s_awindow,s_vspec_cmatch   // match=window + cur_match
600         mov s_vcurmatch=s_vspec_cmatch          // current value
601         add s_vchainlen=-1,s_vchainlen          // --chain_length
602 }{.mib
603         cmp.le.unc p_end,p0=s_vspec_cmatch,s_vlimit
604         and s_vspec_cmatch=s_vspec_cmatch,s_wmask
605 (p_end) br.cond.dptk.many .terminate
606         ;;
607 }{.mmi  // Cycle 1
608         ld1 s_vmatch0=[s_amatch],1              // load match[0]
609         // compute prev[cur_match]:
610         shladd s_vspec_cmatch=s_vspec_cmatch,1,s_aprev
611         cmp.eq.unc p_end,p0=s_vchainlen,r0
612 } {.mib
613         nop.m 0
614         add s_amatblen=s_awinbest,s_vcurmatch   // match=window + cur_match
615 (p_end) br.cond.dptk.many .terminate
616         ;;
617 }{.mmi  // Cycle 2 (short)
618         ld2.nt1 s_vspec_cmatch=[s_vspec_cmatch]         // get next cur_match
619         ;;
620 }{.mmi  // Cycle 3 (short)
621         ld1.nt1 s_vmatbst=[s_amatblen],-1       // load match[best_len]
622         cmp.ne.unc p_ll,p0=r0,r0     // parallel compare initialized as 'false'
623         ;;
624 }{.mmi  // Cycle 4 (short)
625         // load match[1] - - note: match += 3 (in total):
626         ld1.nt1 s_vmatch1=[s_amatch],2
627         ;;
628         // Cycle 5  (short)
629 (p_bn2) ld1.nt1 s_vmatbst1=[s_amatblen]         // load match[best_len-1]
630 }{.mib  // Here we (MOST LIKELY) pay a L2-fetch stall
631         // p_ll switched on as soon as we get a mismatch:
632         cmp.ne.or p_ll,p0=s_vmatch0,s_vscan0
633         cmp.ne.or p_ll,p0=s_vmatbst,s_vscanend
634 (p_ll)  br.cond.dptk.many .next_iter
635         ;;
636 }{.mmi  // Cycle 6
637         ld1.nt1 s_vmatch3=[s_amatch]
638         mova s_vlen=3
639         nop.i 0
640 }{.mib
641         cmp.ne.or p_ll,p0=s_vmatch1,s_vscan1
642 (p_bn2) cmp.ne.or p_ll,p0=s_vmatbst1,s_vscanend1
643 (p_ll)  br.cond.dptk.many .next_iter
644         ;;
645 }
646
647 // We have passed the first hurdle - Are there additional matches ???
648
649 .test_more:
650 {.mmi   // Cycle 0
651         and s_tm3=7,s_ascan                     // get byte offset
652         and s_tm4=7,s_amatch                    // get byte offset
653         movi0 ar.ec=MLAT+SHLAT+2                // NB: One trip more than usual
654 }{.mib
655         cmp.ne.unc p_no,p0=s_vscan3,s_vmatch3   // does not next one differ?
656 (p_no)  br.cond.dptk.many .only3
657         ;;
658 }{.mmi  // Cycle 1
659         and s_tm1=-8,s_ascan    // get aligned address
660         shladd s_tm3=s_tm3,3,r0
661         movi0 ar.lc=31          // 32 times around the loop (8B at a time)
662 }{.mib
663         and s_tm2=-8,s_amatch                   // get aligned address
664         shladd s_tm4=s_tm4,3,r0
665         nop.b 0
666         ;;
667 }{.mmi  // Cycle 2
668         ld8.nt1 scan[1]=[s_tm1],8                       // load first chunk
669         sub s_tm5=64,s_tm3                              // 64 - amount
670         movi0 pr.rot=1<<16
671 }{.mmi
672         ld8.nt1 match[1]=[s_tm2],8      // load first chunk
673         sub s_tm6=64,s_tm4              // 64 - amount
674         add s_vlen=-8,s_vlen            // will be updated at least once
675         ;;
676 }
677         .align 32
678 .cmploop:
679 {.mmi   // Cycle 0
680 (lc[0])                 ld8 scan[0]=[s_tm1],8           // next scan chunk
681 (lc[MLAT+SHLAT+1])      add s_vlen=8,s_vlen
682 (lc[MLAT])              first shscan0[0]=scan[MLAT+1],s_tm3
683 }{.mib
684 (lc[MLAT+SHLAT+1])      cmp.ne.unc p_no,p0=s_tm7,s_tm8  // break search if !=
685 (lc[MLAT])              first shmatch0[0]=match[MLAT+1],s_tm4
686 (p_no)                  br.cond.dpnt.many .mismatch
687                         ;;
688 }{.mii  // Cycle 1
689 (lc[0])                 ld8 match[0]=[s_tm2],8
690                         // shift left(le) or right(be):
691 (lc[MLAT])              second shscan1[0]=scan[MLAT],s_tm5
692 (lc[MLAT])              second shmatch1[0]=match[MLAT],s_tm6
693 }{.mmb
694 (lc[MLAT+SHLAT])        or s_tm7=shscan0[SHLAT],shscan1[SHLAT]
695 (lc[MLAT+SHLAT])        or s_tm8=shmatch0[SHLAT],shmatch1[SHLAT]
696                         br.ctop.dptk.many .cmploop
697                         ;;
698 }{.mfi
699         mov s_vlen=258
700         nop.f 0
701 }{.mfi
702         nop.f 0    // realign
703         ;;
704 }
705 .mismatch:
706 {.mii   // Cycle 0 (short)
707 (p_no)  pcmp1.eq s_tm2=s_tm7,s_tm8      // find first non-matching character
708         nop.i 0
709         ;;
710         // Cycle 1 (short)
711 (p_no)  count s_tm1=s_tm2
712         ;;
713 }{.mib  // Cycle 2 (short)
714 (p_no)  add s_vlen=s_vlen,s_tm1         // effective length
715         nop.i 0
716         clrrrb
717         ;;
718 }
719
720 .only3:
721 {.mib   // Cycle 0 (short)
722         cmp.gt.unc p0,p_nbs=s_vlen,s_vbestlen           // (len > best_len) ?
723 (p_nbs) br.cond.dpnt.many .next_iter                    // if not, re-iternate
724         ;;
725 }{.mmi  // Cycle 1 (short)
726         ld4 s_tm7=[s_anicematch]                        // nice_match
727         st4 [s_amatchstart]= s_vcurmatch
728         add s_ascanend=s_ascan,s_vlen                   // reset with best_len
729         ;;
730 }{.mmi  // Cycle 2 (short)
731         mova s_vbestlen=s_vlen
732         add s_ascanend=-3,s_ascanend            // remember extra offset
733         ;;
734 }{.mmi  // Cycle 3 (short)
735         ld1 s_vscanend=[s_ascanend],-1          // scan_end=scan[best_len]
736         add s_awinbest=s_awindow,s_vbestlen     // update with new best_len
737         cmp.ne.unc p_bn2,p0=2,s_vbestlen        // set if bestlen != 2
738         ;;
739 }{.mib  // Cycle 4 (short)
740         // scan_end1=scan[best_len-1] NB: s_ascanend reset:
741         ld1.nt1 s_vscanend1=[s_ascanend],1
742         cmp.lt.unc p_nnc,p0=s_vlen,s_tm7        // compare with nice_match
743 (p_nnc) br.cond.dptk.many .next_iter
744         ;;
745 }
746 .terminate:
747 {.mii   // Cycle 0/1
748         nop.m 0
749         movi0 ar.lc=s_lcsave
750         movi0 pr=s_prsave,-1
751 }{.mbb
752         nop.m 0
753         nop.b 0
754         br.ret.sptk.many rp     // ret0 is identical to best_len
755         ;;
756 }
757         .endp
758
759         .global match_init
760         .proc match_init
761 match_init:
762         sub ret0=ret0,ret0
763         br.ret.sptk.many rp
764         .endp
765
766 # else
767  error: this asm version is for 386 or 680x0 or ia64 only
768 # endif /* __ia64__ */
769 #endif /* mc68000 || mc68020 */
770 #endif /* i386 || _I386   */