Merge lp:~matthew-gretton-dann/cortex-strings/aarch64-additions-2 into lp:cortex-strings
- aarch64-additions-2
- Merge into trunk
Proposed by
Matthew Gretton-Dann
Status: | Merged |
---|---|
Merged at revision: | 97 |
Proposed branch: | lp:~matthew-gretton-dann/cortex-strings/aarch64-additions-2 |
Merge into: | lp:cortex-strings |
Diff against target: |
569 lines (+530/-2) 4 files modified
Makefile.am (+5/-2) src/aarch64/memcmp.S (+162/-0) src/aarch64/strnlen.S (+164/-0) tests/test-strnlen.c (+199/-0) |
To merge this branch: | bzr merge lp:~matthew-gretton-dann/cortex-strings/aarch64-additions-2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Linaro Toolchain Developers | Pending | ||
Review via email: mp+142147@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Makefile.am' | |||
2 | --- Makefile.am 2013-01-07 14:12:23 +0000 | |||
3 | +++ Makefile.am 2013-01-07 16:09:31 +0000 | |||
4 | @@ -44,7 +44,8 @@ | |||
5 | 44 | tests/test-strcmp \ | 44 | tests/test-strcmp \ |
6 | 45 | tests/test-strcpy \ | 45 | tests/test-strcpy \ |
7 | 46 | tests/test-strlen \ | 46 | tests/test-strlen \ |
9 | 47 | tests/test-strncmp | 47 | tests/test-strncmp \ |
10 | 48 | tests/test-strnlen | ||
11 | 48 | 49 | ||
12 | 49 | # Options for the tests | 50 | # Options for the tests |
13 | 50 | tests_cflags = -I$(srcdir)/tests $(AM_CFLAGS) | 51 | tests_cflags = -I$(srcdir)/tests $(AM_CFLAGS) |
14 | @@ -266,12 +267,14 @@ | |||
15 | 266 | if HOST_AARCH64 | 267 | if HOST_AARCH64 |
16 | 267 | 268 | ||
17 | 268 | libcortex_strings_la_SOURCES = \ | 269 | libcortex_strings_la_SOURCES = \ |
18 | 270 | src/aarch64/memcmp.S \ | ||
19 | 269 | src/aarch64/memcpy.S \ | 271 | src/aarch64/memcpy.S \ |
20 | 270 | src/aarch64/memmove.S \ | 272 | src/aarch64/memmove.S \ |
21 | 271 | src/aarch64/memset.S \ | 273 | src/aarch64/memset.S \ |
22 | 272 | src/aarch64/strcmp.S \ | 274 | src/aarch64/strcmp.S \ |
23 | 273 | src/aarch64/strlen.S \ | 275 | src/aarch64/strlen.S \ |
25 | 274 | src/aarch64/strncmp.S | 276 | src/aarch64/strncmp.S \ |
26 | 277 | src/aarch64/strnlen.S | ||
27 | 275 | 278 | ||
28 | 276 | endif | 279 | endif |
29 | 277 | 280 | ||
30 | 278 | 281 | ||
31 | === added file 'src/aarch64/memcmp.S' | |||
32 | --- src/aarch64/memcmp.S 1970-01-01 00:00:00 +0000 | |||
33 | +++ src/aarch64/memcmp.S 2013-01-07 16:09:31 +0000 | |||
34 | @@ -0,0 +1,162 @@ | |||
35 | 1 | /* memcmp - compare memory | ||
36 | 2 | |||
37 | 3 | Copyright (c) 2013, Linaro Limited | ||
38 | 4 | All rights reserved. | ||
39 | 5 | |||
40 | 6 | Redistribution and use in source and binary forms, with or without | ||
41 | 7 | modification, are permitted provided that the following conditions are met: | ||
42 | 8 | * Redistributions of source code must retain the above copyright | ||
43 | 9 | notice, this list of conditions and the following disclaimer. | ||
44 | 10 | * Redistributions in binary form must reproduce the above copyright | ||
45 | 11 | notice, this list of conditions and the following disclaimer in the | ||
46 | 12 | documentation and/or other materials provided with the distribution. | ||
47 | 13 | * Neither the name of the Linaro nor the | ||
48 | 14 | names of its contributors may be used to endorse or promote products | ||
49 | 15 | derived from this software without specific prior written permission. | ||
50 | 16 | |||
51 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
52 | 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
53 | 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
54 | 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
55 | 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
56 | 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
57 | 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
58 | 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
59 | 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
60 | 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
61 | 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
62 | 28 | |||
63 | 29 | /* Assumptions: | ||
64 | 30 | * | ||
65 | 31 | * ARMv8-a, AArch64 | ||
66 | 32 | */ | ||
67 | 33 | |||
68 | 34 | .macro def_fn f p2align=0 | ||
69 | 35 | .text | ||
70 | 36 | .p2align \p2align | ||
71 | 37 | .global \f | ||
72 | 38 | .type \f, %function | ||
73 | 39 | \f: | ||
74 | 40 | .endm | ||
75 | 41 | |||
76 | 42 | /* Parameters and result. */ | ||
77 | 43 | #define src1 x0 | ||
78 | 44 | #define src2 x1 | ||
79 | 45 | #define limit x2 | ||
80 | 46 | #define result x0 | ||
81 | 47 | |||
82 | 48 | /* Internal variables. */ | ||
83 | 49 | #define data1 x3 | ||
84 | 50 | #define data1w w3 | ||
85 | 51 | #define data2 x4 | ||
86 | 52 | #define data2w w4 | ||
87 | 53 | #define has_nul x5 | ||
88 | 54 | #define diff x6 | ||
89 | 55 | #define endloop x7 | ||
90 | 56 | #define tmp1 x8 | ||
91 | 57 | #define tmp2 x9 | ||
92 | 58 | #define tmp3 x10 | ||
93 | 59 | #define pos x11 | ||
94 | 60 | #define limit_wd x12 | ||
95 | 61 | #define mask x13 | ||
96 | 62 | |||
97 | 63 | def_fn memcmp p2align=6 | ||
98 | 64 | cbz limit, .Lret0 | ||
99 | 65 | eor tmp1, src1, src2 | ||
100 | 66 | tst tmp1, #7 | ||
101 | 67 | b.ne .Lmisaligned8 | ||
102 | 68 | ands tmp1, src1, #7 | ||
103 | 69 | b.ne .Lmutual_align | ||
104 | 70 | add limit_wd, limit, #7 | ||
105 | 71 | lsr limit_wd, limit_wd, #3 | ||
106 | 72 | /* Start of performance-critical section -- one 64B cache line. */ | ||
107 | 73 | .Lloop_aligned: | ||
108 | 74 | ldr data1, [src1], #8 | ||
109 | 75 | ldr data2, [src2], #8 | ||
110 | 76 | .Lstart_realigned: | ||
111 | 77 | subs limit_wd, limit_wd, #1 | ||
112 | 78 | eor diff, data1, data2 /* Non-zero if differences found. */ | ||
113 | 79 | csinv endloop, diff, xzr, ne /* Last Dword or differences. */ | ||
114 | 80 | cbz endloop, .Lloop_aligned | ||
115 | 81 | /* End of performance-critical section -- one 64B cache line. */ | ||
116 | 82 | |||
117 | 83 | /* Not reached the limit, must have found a diff. */ | ||
118 | 84 | cbnz limit_wd, .Lnot_limit | ||
119 | 85 | |||
120 | 86 | /* Limit % 8 == 0 => all bytes significant. */ | ||
121 | 87 | ands limit, limit, #7 | ||
122 | 88 | b.eq .Lnot_limit | ||
123 | 89 | |||
124 | 90 | lsl limit, limit, #3 /* Bits -> bytes. */ | ||
125 | 91 | mov mask, #~0 | ||
126 | 92 | #ifdef __AARCH64EB__ | ||
127 | 93 | lsr mask, mask, limit | ||
128 | 94 | #else | ||
129 | 95 | lsl mask, mask, limit | ||
130 | 96 | #endif | ||
131 | 97 | bic data1, data1, mask | ||
132 | 98 | bic data2, data2, mask | ||
133 | 99 | |||
134 | 100 | orr diff, diff, mask | ||
135 | 101 | .Lnot_limit: | ||
136 | 102 | |||
137 | 103 | #ifndef __AARCH64EB__ | ||
138 | 104 | rev diff, diff | ||
139 | 105 | rev data1, data1 | ||
140 | 106 | rev data2, data2 | ||
141 | 107 | #endif | ||
142 | 108 | /* The MS-non-zero bit of DIFF marks either the first bit | ||
143 | 109 | that is different, or the end of the significant data. | ||
144 | 110 | Shifting left now will bring the critical information into the | ||
145 | 111 | top bits. */ | ||
146 | 112 | clz pos, diff | ||
147 | 113 | lsl data1, data1, pos | ||
148 | 114 | lsl data2, data2, pos | ||
149 | 115 | /* But we need to zero-extend (char is unsigned) the value and then | ||
150 | 116 | perform a signed 32-bit subtraction. */ | ||
151 | 117 | lsr data1, data1, #56 | ||
152 | 118 | sub result, data1, data2, lsr #56 | ||
153 | 119 | ret | ||
154 | 120 | |||
155 | 121 | .Lmutual_align: | ||
156 | 122 | /* Sources are mutually aligned, but are not currently at an | ||
157 | 123 | alignment boundary. Round down the addresses and then mask off | ||
158 | 124 | the bytes that precede the start point. */ | ||
159 | 125 | bic src1, src1, #7 | ||
160 | 126 | bic src2, src2, #7 | ||
161 | 127 | add limit, limit, tmp1 /* Adjust the limit for the extra. */ | ||
162 | 128 | lsl tmp1, tmp1, #3 /* Bytes beyond alignment -> bits. */ | ||
163 | 129 | ldr data1, [src1], #8 | ||
164 | 130 | neg tmp1, tmp1 /* Bits to alignment -64. */ | ||
165 | 131 | ldr data2, [src2], #8 | ||
166 | 132 | mov tmp2, #~0 | ||
167 | 133 | #ifdef __AARCH64EB__ | ||
168 | 134 | /* Big-endian. Early bytes are at MSB. */ | ||
169 | 135 | lsl tmp2, tmp2, tmp1 /* Shift (tmp1 & 63). */ | ||
170 | 136 | #else | ||
171 | 137 | /* Little-endian. Early bytes are at LSB. */ | ||
172 | 138 | lsr tmp2, tmp2, tmp1 /* Shift (tmp1 & 63). */ | ||
173 | 139 | #endif | ||
174 | 140 | add limit_wd, limit, #7 | ||
175 | 141 | orr data1, data1, tmp2 | ||
176 | 142 | orr data2, data2, tmp2 | ||
177 | 143 | lsr limit_wd, limit_wd, #3 | ||
178 | 144 | b .Lstart_realigned | ||
179 | 145 | |||
180 | 146 | .Lret0: | ||
181 | 147 | mov result, #0 | ||
182 | 148 | ret | ||
183 | 149 | |||
184 | 150 | .p2align 6 | ||
185 | 151 | .Lmisaligned8: | ||
186 | 152 | sub limit, limit, #1 | ||
187 | 153 | 1: | ||
188 | 154 | /* Perhaps we can do better than this. */ | ||
189 | 155 | ldrb data1w, [src1], #1 | ||
190 | 156 | ldrb data2w, [src2], #1 | ||
191 | 157 | subs limit, limit, #1 | ||
192 | 158 | ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */ | ||
193 | 159 | b.eq 1b | ||
194 | 160 | sub result, data1, data2 | ||
195 | 161 | ret | ||
196 | 162 | .size memcmp, . - memcmp | ||
197 | 0 | 163 | ||
198 | === added file 'src/aarch64/strnlen.S' | |||
199 | --- src/aarch64/strnlen.S 1970-01-01 00:00:00 +0000 | |||
200 | +++ src/aarch64/strnlen.S 2013-01-07 16:09:31 +0000 | |||
201 | @@ -0,0 +1,164 @@ | |||
202 | 1 | /* strnlen - calculate the length of a string with limit. | ||
203 | 2 | |||
204 | 3 | Copyright (c) 2013, Linaro Limited | ||
205 | 4 | All rights reserved. | ||
206 | 5 | |||
207 | 6 | Redistribution and use in source and binary forms, with or without | ||
208 | 7 | modification, are permitted provided that the following conditions are met: | ||
209 | 8 | * Redistributions of source code must retain the above copyright | ||
210 | 9 | notice, this list of conditions and the following disclaimer. | ||
211 | 10 | * Redistributions in binary form must reproduce the above copyright | ||
212 | 11 | notice, this list of conditions and the following disclaimer in the | ||
213 | 12 | documentation and/or other materials provided with the distribution. | ||
214 | 13 | * Neither the name of the Linaro nor the | ||
215 | 14 | names of its contributors may be used to endorse or promote products | ||
216 | 15 | derived from this software without specific prior written permission. | ||
217 | 16 | |||
218 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
219 | 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
220 | 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
221 | 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
222 | 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
223 | 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
224 | 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
225 | 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
226 | 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
227 | 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
228 | 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
229 | 28 | |||
230 | 29 | /* Assumptions: | ||
231 | 30 | * | ||
232 | 31 | * ARMv8-a, AArch64 | ||
233 | 32 | */ | ||
234 | 33 | |||
235 | 34 | /* Arguments and results. */ | ||
236 | 35 | #define srcin x0 | ||
237 | 36 | #define len x0 | ||
238 | 37 | #define limit x1 | ||
239 | 38 | |||
240 | 39 | /* Locals and temporaries. */ | ||
241 | 40 | #define src x2 | ||
242 | 41 | #define data1 x3 | ||
243 | 42 | #define data2 x4 | ||
244 | 43 | #define data2a x5 | ||
245 | 44 | #define has_nul1 x6 | ||
246 | 45 | #define has_nul2 x7 | ||
247 | 46 | #define tmp1 x8 | ||
248 | 47 | #define tmp2 x9 | ||
249 | 48 | #define tmp3 x10 | ||
250 | 49 | #define tmp4 x11 | ||
251 | 50 | #define zeroones x12 | ||
252 | 51 | #define pos x13 | ||
253 | 52 | #define limit_wd x14 | ||
254 | 53 | |||
255 | 54 | .macro def_fn f p2align=0 | ||
256 | 55 | .text | ||
257 | 56 | .p2align \p2align | ||
258 | 57 | .global \f | ||
259 | 58 | .type \f, %function | ||
260 | 59 | \f: | ||
261 | 60 | .endm | ||
262 | 61 | |||
263 | 62 | #define REP8_01 0x0101010101010101 | ||
264 | 63 | #define REP8_7f 0x7f7f7f7f7f7f7f7f | ||
265 | 64 | #define REP8_80 0x8080808080808080 | ||
266 | 65 | |||
267 | 66 | .text | ||
268 | 67 | .p2align 6 | ||
269 | 68 | .Lstart: | ||
270 | 69 | /* Pre-pad to ensure critical loop begins an icache line. */ | ||
271 | 70 | .rep 7 | ||
272 | 71 | nop | ||
273 | 72 | .endr | ||
274 | 73 | /* Put this code here to avoid wasting more space with pre-padding. */ | ||
275 | 74 | .Lhit_limit: | ||
276 | 75 | mov len, limit | ||
277 | 76 | ret | ||
278 | 77 | |||
279 | 78 | def_fn strnlen | ||
280 | 79 | cbz limit, .Lhit_limit | ||
281 | 80 | mov zeroones, #REP8_01 | ||
282 | 81 | bic src, srcin, #15 | ||
283 | 82 | ands tmp1, srcin, #15 | ||
284 | 83 | b.ne .Lmisaligned | ||
285 | 84 | add limit_wd, limit, #15 | ||
286 | 85 | lsr limit_wd, limit_wd, #4 | ||
287 | 86 | /* NUL detection works on the principle that (X - 1) & (~X) & 0x80 | ||
288 | 87 | (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and | ||
289 | 88 | can be done in parallel across the entire word. */ | ||
290 | 89 | /* The inner loop deals with two Dwords at a time. This has a | ||
291 | 90 | slightly higher start-up cost, but we should win quite quickly, | ||
292 | 91 | especially on cores with a high number of issue slots per | ||
293 | 92 | cycle, as we get much better parallelism out of the operations. */ | ||
294 | 93 | |||
295 | 94 | /* Start of critial section -- keep to one 64Byte cache line. */ | ||
296 | 95 | .Lloop: | ||
297 | 96 | ldp data1, data2, [src], #16 | ||
298 | 97 | .Lrealigned: | ||
299 | 98 | sub tmp1, data1, zeroones | ||
300 | 99 | orr tmp2, data1, #REP8_7f | ||
301 | 100 | sub tmp3, data2, zeroones | ||
302 | 101 | orr tmp4, data2, #REP8_7f | ||
303 | 102 | bic has_nul1, tmp1, tmp2 | ||
304 | 103 | bic has_nul2, tmp3, tmp4 | ||
305 | 104 | subs limit_wd, limit_wd, #1 | ||
306 | 105 | orr tmp1, has_nul1, has_nul2 | ||
307 | 106 | ccmp tmp1, #0, #0, ne /* NZCV = 0000 */ | ||
308 | 107 | b.eq .Lloop | ||
309 | 108 | /* End of critical section -- keep to one 64Byte cache line. */ | ||
310 | 109 | |||
311 | 110 | orr tmp1, has_nul1, has_nul2 | ||
312 | 111 | cbz tmp1, .Lhit_limit /* No null in final Qword. */ | ||
313 | 112 | |||
314 | 113 | /* We know there's a null in the final Qword. The easiest thing | ||
315 | 114 | to do now is work out the length of the string and return | ||
316 | 115 | MIN (len, limit). */ | ||
317 | 116 | |||
318 | 117 | sub len, src, srcin | ||
319 | 118 | cbz has_nul1, .Lnul_in_data2 | ||
320 | 119 | #ifdef __AARCH64EB__ | ||
321 | 120 | mov data2, data1 | ||
322 | 121 | #endif | ||
323 | 122 | sub len, len, #8 | ||
324 | 123 | mov has_nul2, has_nul1 | ||
325 | 124 | .Lnul_in_data2: | ||
326 | 125 | #ifdef __AARCH64EB__ | ||
327 | 126 | /* For big-endian, carry propagation (if the final byte in the | ||
328 | 127 | string is 0x01) means we cannot use has_nul directly. The | ||
329 | 128 | easiest way to get the correct byte is to byte-swap the data | ||
330 | 129 | and calculate the syndrome a second time. */ | ||
331 | 130 | rev data2, data2 | ||
332 | 131 | sub tmp1, data2, zeroones | ||
333 | 132 | orr tmp2, data2, #REP8_7f | ||
334 | 133 | bic has_nul2, tmp1, tmp2 | ||
335 | 134 | #endif | ||
336 | 135 | sub len, len, #8 | ||
337 | 136 | rev has_nul2, has_nul2 | ||
338 | 137 | clz pos, has_nul2 | ||
339 | 138 | add len, len, pos, lsr #3 /* Bits to bytes. */ | ||
340 | 139 | cmp len, limit | ||
341 | 140 | csel len, len, limit, ls /* Return the lower value. */ | ||
342 | 141 | ret | ||
343 | 142 | |||
344 | 143 | .Lmisaligned: | ||
345 | 144 | add tmp3, limit, tmp1 | ||
346 | 145 | cmp tmp1, #8 | ||
347 | 146 | neg tmp1, tmp1 | ||
348 | 147 | ldp data1, data2, [src], #16 | ||
349 | 148 | add limit_wd, tmp3, #15 | ||
350 | 149 | lsl tmp1, tmp1, #3 /* Bytes beyond alignment -> bits. */ | ||
351 | 150 | mov tmp2, #~0 | ||
352 | 151 | lsr limit_wd, limit_wd, #4 | ||
353 | 152 | #ifdef __AARCH64EB__ | ||
354 | 153 | /* Big-endian. Early bytes are at MSB. */ | ||
355 | 154 | lsl tmp2, tmp2, tmp1 /* Shift (tmp1 & 63). */ | ||
356 | 155 | #else | ||
357 | 156 | /* Little-endian. Early bytes are at LSB. */ | ||
358 | 157 | lsr tmp2, tmp2, tmp1 /* Shift (tmp1 & 63). */ | ||
359 | 158 | #endif | ||
360 | 159 | orr data1, data1, tmp2 | ||
361 | 160 | orr data2a, data2, tmp2 | ||
362 | 161 | csinv data1, data1, xzr, le | ||
363 | 162 | csel data2, data2, data2a, le | ||
364 | 163 | b .Lrealigned | ||
365 | 164 | .size strnlen, . - .Lstart /* Include pre-padding in size. */ | ||
366 | 0 | 165 | ||
367 | === added file 'tests/test-strnlen.c' | |||
368 | --- tests/test-strnlen.c 1970-01-01 00:00:00 +0000 | |||
369 | +++ tests/test-strnlen.c 2013-01-07 16:09:31 +0000 | |||
370 | @@ -0,0 +1,199 @@ | |||
371 | 1 | /* Test and measure strlen functions. | ||
372 | 2 | Copyright (C) 1999-2012 Free Software Foundation, Inc. | ||
373 | 3 | This file is part of the GNU C Library. | ||
374 | 4 | Written by Jakub Jelinek <jakub@redhat.com>, 1999. | ||
375 | 5 | |||
376 | 6 | The GNU C Library is free software; you can redistribute it and/or | ||
377 | 7 | modify it under the terms of the GNU Lesser General Public | ||
378 | 8 | License as published by the Free Software Foundation; either | ||
379 | 9 | version 2.1 of the License, or (at your option) any later version. | ||
380 | 10 | |||
381 | 11 | The GNU C Library is distributed in the hope that it will be useful, | ||
382 | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
383 | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
384 | 14 | Lesser General Public License for more details. | ||
385 | 15 | |||
386 | 16 | You should have received a copy of the GNU Lesser General Public | ||
387 | 17 | License along with the GNU C Library; if not, see | ||
388 | 18 | <http://www.gnu.org/licenses/>. */ | ||
389 | 19 | |||
390 | 20 | #define TEST_MAIN | ||
391 | 21 | #define TEST_NAME "strnlen" | ||
392 | 22 | #include "test-string.h" | ||
393 | 23 | |||
394 | 24 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | ||
395 | 25 | |||
396 | 26 | typedef size_t (*proto_t) (const char *, size_t); | ||
397 | 27 | size_t simple_strnlen (const char *, size_t); | ||
398 | 28 | |||
399 | 29 | IMPL (simple_strnlen, 0) | ||
400 | 30 | IMPL (strnlen, 1) | ||
401 | 31 | |||
402 | 32 | size_t | ||
403 | 33 | simple_strnlen (const char *s, size_t maxlen) | ||
404 | 34 | { | ||
405 | 35 | size_t i; | ||
406 | 36 | |||
407 | 37 | for (i = 0; i < maxlen && s[i]; ++i); | ||
408 | 38 | return i; | ||
409 | 39 | } | ||
410 | 40 | |||
411 | 41 | static void | ||
412 | 42 | do_one_test (impl_t *impl, const char *s, size_t maxlen, size_t exp_len) | ||
413 | 43 | { | ||
414 | 44 | size_t len = CALL (impl, s, maxlen); | ||
415 | 45 | if (len != exp_len) | ||
416 | 46 | { | ||
417 | 47 | error (0, 0, "Wrong result in function %s %zd %zd", impl->name, | ||
418 | 48 | len, exp_len); | ||
419 | 49 | ret = 1; | ||
420 | 50 | return; | ||
421 | 51 | } | ||
422 | 52 | |||
423 | 53 | if (HP_TIMING_AVAIL) | ||
424 | 54 | { | ||
425 | 55 | hp_timing_t start __attribute ((unused)); | ||
426 | 56 | hp_timing_t stop __attribute ((unused)); | ||
427 | 57 | hp_timing_t best_time = ~ (hp_timing_t) 0; | ||
428 | 58 | size_t i; | ||
429 | 59 | |||
430 | 60 | for (i = 0; i < 32; ++i) | ||
431 | 61 | { | ||
432 | 62 | HP_TIMING_NOW (start); | ||
433 | 63 | CALL (impl, s, maxlen); | ||
434 | 64 | HP_TIMING_NOW (stop); | ||
435 | 65 | HP_TIMING_BEST (best_time, start, stop); | ||
436 | 66 | } | ||
437 | 67 | |||
438 | 68 | printf ("\t%zd", (size_t) best_time); | ||
439 | 69 | } | ||
440 | 70 | } | ||
441 | 71 | |||
442 | 72 | static void | ||
443 | 73 | do_test (size_t align, size_t len, size_t maxlen, int max_char) | ||
444 | 74 | { | ||
445 | 75 | size_t i; | ||
446 | 76 | |||
447 | 77 | align &= 7; | ||
448 | 78 | if (align + len >= page_size) | ||
449 | 79 | return; | ||
450 | 80 | |||
451 | 81 | for (i = 0; i < len; ++i) | ||
452 | 82 | buf1[align + i] = 1 + 7 * i % max_char; | ||
453 | 83 | buf1[align + len] = 0; | ||
454 | 84 | |||
455 | 85 | if (HP_TIMING_AVAIL) | ||
456 | 86 | printf ("Length %4zd, alignment %2zd:", len, align); | ||
457 | 87 | |||
458 | 88 | FOR_EACH_IMPL (impl, 0) | ||
459 | 89 | do_one_test (impl, (char *) (buf1 + align), maxlen, MIN (len, maxlen)); | ||
460 | 90 | |||
461 | 91 | if (HP_TIMING_AVAIL) | ||
462 | 92 | putchar ('\n'); | ||
463 | 93 | } | ||
464 | 94 | |||
465 | 95 | static void | ||
466 | 96 | do_random_tests (void) | ||
467 | 97 | { | ||
468 | 98 | size_t i, j, n, align, len; | ||
469 | 99 | unsigned char *p = buf1 + page_size - 512; | ||
470 | 100 | |||
471 | 101 | for (n = 0; n < ITERATIONS; n++) | ||
472 | 102 | { | ||
473 | 103 | align = random () & 15; | ||
474 | 104 | len = random () & 511; | ||
475 | 105 | if (len + align > 510) | ||
476 | 106 | len = 511 - align - (random () & 7); | ||
477 | 107 | j = len + align + 64; | ||
478 | 108 | if (j > 512) | ||
479 | 109 | j = 512; | ||
480 | 110 | |||
481 | 111 | for (i = 0; i < j; i++) | ||
482 | 112 | { | ||
483 | 113 | if (i == len + align) | ||
484 | 114 | p[i] = 0; | ||
485 | 115 | else | ||
486 | 116 | { | ||
487 | 117 | p[i] = random () & 255; | ||
488 | 118 | if (i >= align && i < len + align && !p[i]) | ||
489 | 119 | p[i] = (random () & 127) + 1; | ||
490 | 120 | } | ||
491 | 121 | } | ||
492 | 122 | |||
493 | 123 | FOR_EACH_IMPL (impl, 1) | ||
494 | 124 | { | ||
495 | 125 | if (len > 0 | ||
496 | 126 | && CALL (impl, (char *) (p + align), len - 1) != len - 1) | ||
497 | 127 | { | ||
498 | 128 | error (0, 0, "Iteration %zd (limited) - wrong result in function %s (%zd) %zd != %zd, p %p", | ||
499 | 129 | n, impl->name, align, | ||
500 | 130 | CALL (impl, (char *) (p + align), len - 1), len - 1, p); | ||
501 | 131 | ret = 1; | ||
502 | 132 | } | ||
503 | 133 | if (CALL (impl, (char *) (p + align), len) != len) | ||
504 | 134 | { | ||
505 | 135 | error (0, 0, "Iteration %zd (exact) - wrong result in function %s (%zd) %zd != %zd, p %p", | ||
506 | 136 | n, impl->name, align, | ||
507 | 137 | CALL (impl, (char *) (p + align), len), len, p); | ||
508 | 138 | ret = 1; | ||
509 | 139 | } | ||
510 | 140 | if (CALL (impl, (char *) (p + align), len + 1) != len) | ||
511 | 141 | { | ||
512 | 142 | error (0, 0, "Iteration %zd (long) - wrong result in function %s (%zd) %zd != %zd, p %p", | ||
513 | 143 | n, impl->name, align, | ||
514 | 144 | CALL (impl, (char *) (p + align), len + 1), len, p); | ||
515 | 145 | ret = 1; | ||
516 | 146 | } | ||
517 | 147 | } | ||
518 | 148 | } | ||
519 | 149 | } | ||
520 | 150 | |||
521 | 151 | int | ||
522 | 152 | test_main (void) | ||
523 | 153 | { | ||
524 | 154 | size_t i; | ||
525 | 155 | |||
526 | 156 | test_init (); | ||
527 | 157 | |||
528 | 158 | printf ("%20s", ""); | ||
529 | 159 | FOR_EACH_IMPL (impl, 0) | ||
530 | 160 | printf ("\t%s", impl->name); | ||
531 | 161 | putchar ('\n'); | ||
532 | 162 | |||
533 | 163 | for (i = 1; i < 8; ++i) | ||
534 | 164 | { | ||
535 | 165 | do_test (0, i, i - 1, 127); | ||
536 | 166 | do_test (0, i, i, 127); | ||
537 | 167 | do_test (0, i, i + 1, 127); | ||
538 | 168 | } | ||
539 | 169 | |||
540 | 170 | for (i = 1; i < 8; ++i) | ||
541 | 171 | { | ||
542 | 172 | do_test (i, i, i - 1, 127); | ||
543 | 173 | do_test (i, i, i, 127); | ||
544 | 174 | do_test (i, i, i + 1, 127); | ||
545 | 175 | } | ||
546 | 176 | |||
547 | 177 | for (i = 2; i <= 10; ++i) | ||
548 | 178 | { | ||
549 | 179 | do_test (0, 1 << i, 5000, 127); | ||
550 | 180 | do_test (1, 1 << i, 5000, 127); | ||
551 | 181 | } | ||
552 | 182 | |||
553 | 183 | for (i = 1; i < 8; ++i) | ||
554 | 184 | do_test (0, i, 5000, 255); | ||
555 | 185 | |||
556 | 186 | for (i = 1; i < 8; ++i) | ||
557 | 187 | do_test (i, i, 5000, 255); | ||
558 | 188 | |||
559 | 189 | for (i = 2; i <= 10; ++i) | ||
560 | 190 | { | ||
561 | 191 | do_test (0, 1 << i, 5000, 255); | ||
562 | 192 | do_test (1, 1 << i, 5000, 255); | ||
563 | 193 | } | ||
564 | 194 | |||
565 | 195 | do_random_tests (); | ||
566 | 196 | return ret; | ||
567 | 197 | } | ||
568 | 198 | |||
569 | 199 | #include "test-skeleton.c" |