Update.
[glibc.git] / sysdeps / alpha / strcmp.S
blob8633a6cb56743ac89ae5b0ac93a3198c569535d7
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2    Contributed by Richard Henderson (rth@tamu.edu)
3    This file is part of the GNU C Library.
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
20 /* Bytewise compare two null-terminated strings.  */
22 #include <sysdep.h>
24         .set noat
25         .set noreorder
27         .text
29 ENTRY(strcmp)
30 #ifdef PROF
31         ldgp    gp, 0(pv)
32         lda     AT, _mcount
33         jmp     AT, (AT), _mcount
34         .prologue 1
35 #else
36         .prologue 0
37 #endif
39         ldq_u   t0, 0(a0)       # e0    : give cache time to catch up
40         xor     a0, a1, t2      # .. e1 : are s1 and s2 co-aligned?
41         ldq_u   t1, 0(a1)       # e0    :
42         and     t2, 7, t2       # .. e1 :
43         lda     t3, -1          # e0    :
44         bne     t2, $unaligned  # .. e1 :
46         /* On entry to this basic block:
47            t0 == the first destination word for masking back in
48            t1 == the first source word.
49            t3 == -1.  */
51 $aligned:
52         mskqh   t3, a0, t3      # e0    :
53         nop                     # .. e1 :
54         ornot   t1, t3, t1      # e0    :
55         ornot   t0, t3, t0      # .. e1 :
56         cmpbge  zero, t1, t7    # e0    : bits set iff null found
57         bne     t7, $eos        # e1 (zdb)
59         /* Aligned compare main loop.
60            On entry to this basic block:
61            t0 == an s1 word.
62            t1 == an s2 word not containing a null.  */
64 $a_loop:
65         xor     t0, t1, t2      # e0    :
66         bne     t2, $wordcmp    # .. e1 (zdb)
67         ldq_u   t1, 8(a1)       # e0    :
68         ldq_u   t0, 8(a0)       # .. e1 :
69         addq    a1, 8, a1       # e0    :
70         addq    a0, 8, a0       # .. e1 :
71         cmpbge  zero, t1, t7    # e0    :
72         beq     t7, $a_loop     # .. e1 (zdb)
73         br      $eos            # e1    :
75         /* The two strings are not co-aligned.  Align s1 and cope.  */
77 $unaligned:
78         and     a0, 7, t4       # e0    : find s1 misalignment
79         and     a1, 7, t5       # .. e1 : find s2 misalignment
80         subq    a1, t4, a1      # e0    :
82         /* If s2 misalignment is larger than s2 misalignment, we need
83            extra startup checks to avoid SEGV.  */
85         cmplt   t4, t5, t8      # .. e1 :
86         beq     t8, $u_head     # e1    :
88         mskqh   t3, t5, t3      # e0    :
89         ornot   t1, t3, t3      # e0    :
90         cmpbge  zero, t3, t7    # e1    : is there a zero?
91         beq     t7, $u_head     # e1    :
93         /* We've found a zero in the first partial word of s2.  Align
94            our current s1 and s2 words and compare what we've got.  */
96         extql   t1, t5, t1      # e0    :
97         extql   t0, a0, t0      # e0    :
98         cmpbge  zero, t1, t7    # .. e1 : find that zero again
99         br      $eos            # e1    : and finish up
101         .align 3
102 $u_head:
103         /* We know just enough now to be able to assemble the first
104            full word of s2.  We can still find a zero at the end of it.
106            On entry to this basic block:
107            t0 == first word of s1
108            t1 == first partial word of s2.  */
110         ldq_u   t2, 8(a1)       # e0    : load second partial s2 word
111         lda     t3, -1          # .. e1 : create leading garbage mask
112         extql   t1, a1, t1      # e0    : create first s2 word
113         mskqh   t3, a0, t3      # e0    :
114         extqh   t2, a1, t4      # e0    :
115         ornot   t0, t3, t0      # .. e1 : kill s1 garbage
116         or      t1, t4, t1      # e0    : s2 word now complete
117         cmpbge  zero, t0, t7    # .. e1 : find zero in first s1 word
118         ornot   t1, t3, t1      # e0    : kill s2 garbage
119         lda     t3, -1          # .. e1 :
120         mskql   t3, a1, t3      # e0    : mask for s2[1] bits we have seen
121         bne     t7, $eos        # .. e1 :
122         xor     t0, t1, t4      # e0    : compare aligned words
123         bne     t4, $wordcmp    # .. e1 (zdb)
124         or      t2, t3, t3      # e0    :
125         cmpbge  zero, t3, t7    # e1    :
126         bne     t7, $u_final    # e1    :
128         /* Unaligned copy main loop.  In order to avoid reading too much,
129            the loop is structured to detect zeros in aligned words from s2.
130            This has, unfortunately, effectively pulled half of a loop
131            iteration out into the head and half into the tail, but it does
132            prevent nastiness from accumulating in the very thing we want
133            to run as fast as possible.
135            On entry to this basic block:
136            t2 == the unshifted low-bits from the next s2 word.  */
138         .align 3
139 $u_loop:
140         extql   t2, a1, t3      # e0    :
141         ldq_u   t2, 16(a1)      # .. e1 : load next s2 high bits
142         ldq_u   t0, 8(a0)       # e0    : load next s1 word
143         addq    a1, 8, a1       # .. e1 :
144         addq    a0, 8, a0       # e0    :
145         nop                     # .. e1 :
146         extqh   t2, a1, t1      # e0    :
147         cmpbge  zero, t0, t7    # .. e1 : find zero in current s1 word
148         or      t1, t3, t1      # e0    :
149         bne     t7, $eos        # .. e1 :
150         xor     t0, t1, t4      # e0    : compare the words
151         bne     t4, $wordcmp    # .. e1 (zdb)
152         cmpbge  zero, t2, t4    # e0    : find zero in next low bits
153         beq     t4, $u_loop     # .. e1 (zdb)
155         /* We've found a zero in the low bits of the last s2 word.  Get
156            the next s1 word and align them.  */
157 $u_final:
158         ldq_u   t0, 8(a0)       # e1    :
159         extql   t2, a1, t1      # .. e0 :
160         cmpbge  zero, t1, t7    # e0    :
162         /* We've found a zero somewhere in a word we just read.
163            On entry to this basic block:
164            t0 == s1 word
165            t1 == s2 word
166            t7 == cmpbge mask containing the zero.  */
168         .align 3
169 $eos:
170         negq    t7, t6          # e0    : create bytemask of valid data
171         and     t6, t7, t8      # e1    :
172         subq    t8, 1, t6       # e0    :
173         or      t6, t8, t7      # e1    :
174         zapnot  t0, t7, t0      # e0    : kill the garbage
175         zapnot  t1, t7, t1      # .. e1 :
176         xor     t0, t1, v0      # e0    : and compare
177         beq     v0, $done       # .. e1 :
179         /* Here we have two differing co-aligned words in t0 & t1.
180            Bytewise compare them and return (t0 > t1 ? 1 : -1).  */
181 $wordcmp:
182         cmpbge  t0, t1, t2      # e0    : comparison yields bit mask of ge
183         cmpbge  t1, t0, t3      # .. e1 :
184         xor     t2, t3, t0      # e0    : bits set iff t0/t1 bytes differ
185         negq    t0, t1          # e1    : clear all but least bit
186         and     t0, t1, t0      # e0    :
187         lda     v0, -1          # .. e1 :
188         and     t0, t2, t1      # e0    : was bit set in t0 > t1?
189         cmovne  t1, 1, v0       # .. e1 (zdb)
191 $done:
192         ret                     # e1    :
194         END(strcmp)