]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/alpha/strncmp.S
* sysdeps/alpha/strncmp.S: Don't read too much data when pointers
[thirdparty/glibc.git] / sysdeps / alpha / strncmp.S
1 /* Copyright (C) 1996, 1997, 2003 Free Software Foundation, Inc.
2 Contributed by Richard Henderson (rth@tamu.edu)
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 /* Bytewise compare two null-terminated strings of length no longer than N. */
21
22 #include <sysdep.h>
23
24 .set noat
25 .set noreorder
26
27 .text
28
29 ENTRY(strncmp)
30 #ifdef PROF
31 ldgp gp, 0(pv)
32 lda AT, _mcount
33 jsr AT, (AT), _mcount
34 .prologue 1
35 #else
36 .prologue 0
37 #endif
38
39 xor a0, a1, t2 # e0 : are s1 and s2 co-aligned?
40 beq a2, $zerolength # .. e1 :
41 ldq_u t0, 0(a0) # e0 : give cache time to catch up
42 ldq_u t1, 0(a1) # .. e1 :
43 and t2, 7, t2 # e0 :
44 and a0, 7, t4 # .. e1 : find s1 misalignment
45 lda t3, -1 # e0 :
46 addq a2, t4, a2 # .. e1 : bias count by s1 misalignment
47 and a2, 7, t10 # e1 : ofs of last byte in last word
48 srl a2, 3, a2 # .. e0 : remaining full words in count
49 and a1, 7, t5 # e0 : find s2 misalignment
50 bne t2, $unaligned # .. e1 :
51
52 /* On entry to this basic block:
53 t0 == the first word of s1.
54 t1 == the first word of s2.
55 t3 == -1. */
56
57 $aligned:
58 mskqh t3, a1, t3 # e0 : mask off leading garbage
59 nop # .. e1 :
60 ornot t1, t3, t1 # e0 :
61 ornot t0, t3, t0 # .. e1 :
62 cmpbge zero, t1, t7 # e0 : bits set iff null found
63 beq a2, $eoc # .. e1 : check end of count
64 unop # e0 :
65 bne t7, $eos # .. e1 :
66 unop # e0 :
67 beq t10, $ant_loop # .. e1 :
68
69 /* Aligned compare main loop.
70 On entry to this basic block:
71 t0 == an s1 word.
72 t1 == an s2 word not containing a null. */
73
74 $a_loop:
75 xor t0, t1, t2 # e0 :
76 bne t2, $wordcmp # .. e1 (zdb)
77 ldq_u t1, 8(a1) # e0 :
78 ldq_u t0, 8(a0) # .. e1 :
79 subq a2, 1, a2 # e0 :
80 addq a1, 8, a1 # .. e1 :
81 addq a0, 8, a0 # e0 :
82 beq a2, $eoc # .. e1 :
83 cmpbge zero, t1, t7 # e0 :
84 beq t7, $a_loop # .. e1 :
85 unop # e0 :
86 br $eos # .. e1 :
87
88 /* Alternate aligned compare loop, for when there's no trailing
89 bytes on the count. We have to avoid reading too much data. */
90 $ant_loop:
91 xor t0, t1, t2 # e0 :
92 bne t2, $wordcmp # .. e1 (zdb)
93 subq a2, 1, a2 # e0 :
94 beq a2, $zerolength # .. e1 :
95 ldq_u t1, 8(a1) # e0 :
96 ldq_u t0, 8(a0) # .. e1 :
97 addq a1, 8, a1 # e0 :
98 addq a0, 8, a0 # .. e1 :
99 cmpbge zero, t1, t7 # e0 :
100 beq t7, $ant_loop # .. e1 :
101 unop # e0 :
102 br $eos # .. e1 :
103
104 /* The two strings are not co-aligned. Align s1 and cope. */
105 $unaligned:
106 subq a1, t4, a1 # e0 :
107 unop # :
108
109 /* If s2 misalignment is larger than s2 misalignment, we need
110 extra startup checks to avoid SEGV. */
111
112 cmplt t4, t5, t8 # .. e1 :
113 beq t8, $u_head # e1 :
114
115 mskqh t3, t5, t3 # e0 :
116 ornot t1, t3, t3 # e0 :
117 cmpbge zero, t3, t7 # e1 : is there a zero?
118 beq t7, $u_head # e1 :
119
120 /* We've found a zero in the first partial word of s2. Align
121 our current s1 and s2 words and compare what we've got. */
122
123 extql t1, t5, t1 # e0 :
124 lda t3, -1 # .. e1 :
125 insql t1, a0, t1 # e0 :
126 mskqh t3, a0, t3 # e0 :
127 ornot t1, t3, t1 # e0 :
128 ornot t0, t3, t0 # .. e1 :
129 cmpbge zero, t1, t7 # e0 : find that zero again
130 beq a2, $eoc # .. e1 : and finish up
131 br $eos # e1 :
132
133 .align 3
134 $u_head:
135 /* We know just enough now to be able to assemble the first
136 full word of s2. We can still find a zero at the end of it.
137
138 On entry to this basic block:
139 t0 == first word of s1
140 t1 == first partial word of s2. */
141
142 ldq_u t2, 8(a1) # e0 : load second partial s2 word
143 lda t3, -1 # .. e1 : create leading garbage mask
144 extql t1, a1, t1 # e0 : create first s2 word
145 mskqh t3, a0, t3 # e0 :
146 extqh t2, a1, t4 # e0 :
147 ornot t0, t3, t0 # .. e1 : kill s1 garbage
148 or t1, t4, t1 # e0 : s2 word now complete
149 ornot t1, t3, t1 # e1 : kill s2 garbage
150 cmpbge zero, t0, t7 # e0 : find zero in first s1 word
151 beq a2, $eoc # .. e1 :
152 lda t3, -1 # e0 :
153 bne t7, $eos # .. e1 :
154 subq a2, 1, a2 # e0 :
155 xor t0, t1, t4 # .. e1 : compare aligned words
156 mskql t3, a1, t3 # e0 : mask out s2[1] bits we have seen
157 bne t4, $wordcmp # .. e1 :
158 or t2, t3, t3 # e0 :
159 cmpbge zero, t3, t7 # e1 : find zero in high bits of s2[1]
160 bne t7, $u_final # e1 :
161
162 /* Unaligned copy main loop. In order to avoid reading too much,
163 the loop is structured to detect zeros in aligned words from s2.
164 This has, unfortunately, effectively pulled half of a loop
165 iteration out into the head and half into the tail, but it does
166 prevent nastiness from accumulating in the very thing we want
167 to run as fast as possible.
168
169 On entry to this basic block:
170 t2 == the unshifted low-bits from the next s2 word. */
171
172 .align 3
173 $u_loop:
174 extql t2, a1, t3 # e0 :
175 ldq_u t2, 16(a1) # .. e1 : load next s2 high bits
176 ldq_u t0, 8(a0) # e0 : load next s1 word
177 addq a1, 8, a1 # .. e1 :
178 addq a0, 8, a0 # e0 :
179 nop # .. e1 :
180 extqh t2, a1, t1 # e0 :
181 cmpbge zero, t0, t7 # .. e1 : find zero in current s1 word
182 or t1, t3, t1 # e0 :
183 beq a2, $eoc # .. e1 : check for end of count
184 subq a2, 1, a2 # e0 :
185 bne t7, $eos # .. e1 :
186 xor t0, t1, t4 # e0 : compare the words
187 bne t4, $wordcmp # .. e1 (zdb)
188 cmpbge zero, t2, t4 # e0 : find zero in next low bits
189 beq t4, $u_loop # .. e1 (zdb)
190
191 /* We've found a zero in the low bits of the last s2 word. Get
192 the next s1 word and align them. */
193 $u_final:
194 ldq_u t0, 8(a0) # e1 :
195 extql t2, a1, t1 # .. e0 :
196 cmpbge zero, t1, t7 # e0 :
197 bne a2, $eos # .. e1 :
198
199 /* We've hit end of count. Zero everything after the count
200 and compare whats left. */
201
202 .align 3
203 $eoc:
204 mskql t0, t10, t0
205 mskql t1, t10, t1
206 unop
207 cmpbge zero, t1, t7
208
209 /* We've found a zero somewhere in a word we just read.
210 On entry to this basic block:
211 t0 == s1 word
212 t1 == s2 word
213 t7 == cmpbge mask containing the zero. */
214
215 $eos:
216 negq t7, t6 # e0 : create bytemask of valid data
217 and t6, t7, t8 # e1 :
218 subq t8, 1, t6 # e0 :
219 or t6, t8, t7 # e1 :
220 zapnot t0, t7, t0 # e0 : kill the garbage
221 zapnot t1, t7, t1 # .. e1 :
222 xor t0, t1, v0 # e0 : and compare
223 beq v0, $done # .. e1 :
224
225 /* Here we have two differing co-aligned words in t0 & t1.
226 Bytewise compare them and return (t0 > t1 ? 1 : -1). */
227 .align 3
228 $wordcmp:
229 cmpbge t0, t1, t2 # e0 : comparison yields bit mask of ge
230 cmpbge t1, t0, t3 # .. e1 :
231 xor t2, t3, t0 # e0 : bits set iff t0/t1 bytes differ
232 negq t0, t1 # e1 : clear all but least bit
233 and t0, t1, t0 # e0 :
234 lda v0, -1 # .. e1 :
235 and t0, t2, t1 # e0 : was bit set in t0 > t1?
236 cmovne t1, 1, v0 # .. e1 (zdb)
237
238 $done:
239 ret # e1 :
240
241 .align 3
242 $zerolength:
243 clr v0
244 ret
245
246 END(strncmp)
247 libc_hidden_builtin_def (strncmp)