1 /* 2 * Copyright (c) 2010 MIPS Technologies, Inc. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with 15 * the distribution. 16 * * Neither the name of MIPS Technologies Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <string.h> 34 #include "mips-string-ops.h" 35 36 #define do_strlen_word(__av) {\ 37 if (detect_zero(x,x,_01s,_80s)) break;\ 38 x = __av;\ 39 cnt += sizeof (unsigned);\ 40 } 41 42 #define do_strlen_byte(__x) {\ 43 if ((bx.b.B##__x) == 0) break;\ 44 ++cnt;\ 45 } 46 47 #if SMOKE_TEST_MIPS_STRLEN 48 #define strlen my_strlen 49 #endif 50 51 size_t 52 strlen (const char *_a) 53 { 54 int cnt = 0; 55 unsigned long x; 56 57 /* align the string to word boundary so we can do word at a time. */ 58 if ((cvt_ptr_to (unsigned long, _a) & (sizeof (unsigned long) - 1)) != 0) 59 { 60 if ((cvt_ptr_to (unsigned long, _a) & 1) != 0) 61 { 62 if (get_byte (_a, 0) == 0) 63 return cnt; 64 /* set bit 1 so 2-bytes are checked and incremented. */ 65 inc_ptr_as (char *, _a, 1); 66 ++cnt; 67 } 68 if ((cvt_ptr_to (unsigned long, _a) & 2) != 0) 69 { 70 if (get_byte (_a, 0) == 0) 71 return cnt + 0; 72 if (get_byte (_a, 1) == 0) 73 return cnt + 1; 74 inc_ptr_as (char *, _a, 2); 75 cnt += 2; 76 } 77 } 78 79 #if __mips64 80 #error strlen: mips64 check for 4-byte alignment not implemented. 81 #endif 82 83 if (1) 84 { 85 def_and_set_01 (_01s); 86 def_and_set_80 (_80s); 87 88 /* as advantagous as it is to performance, this code cannot pre-load 89 the following word, nor can it prefetch the next line at the start 90 of the loop since the string can be at the end of a page with the 91 following page unmapped. There are tests in the suite to catch 92 any attempt to go beyond the current word. */ 93 x = get_word (_a, 0); 94 while (1) 95 { 96 /* doing 8 words should cover most strings. */ 97 do_strlen_word (get_word (_a, 1)); 98 do_strlen_word (get_word (_a, 2)); 99 do_strlen_word (get_word (_a, 3)); 100 do_strlen_word (get_word (_a, 4)); 101 do_strlen_word (get_word (_a, 5)); 102 do_strlen_word (get_word (_a, 6)); 103 do_strlen_word (get_word (_a, 7)); 104 do_strlen_word (get_word (_a, 8)); 105 inc_ptr_as (unsigned long*, _a, 8); 106 } 107 } 108 while (1) 109 { 110 /* pull apart the last word processed and find the zero. */ 111 bitfields_t bx; 112 bx.v = x; 113 #if __mips64 114 do_strlen_byte (0); 115 do_strlen_byte (1); 116 do_strlen_byte (2); 117 do_strlen_byte (3); 118 do_strlen_byte (4); 119 do_strlen_byte (5); 120 do_strlen_byte (6); 121 #else 122 do_strlen_byte (0); 123 do_strlen_byte (1); 124 do_strlen_byte (2); 125 #endif 126 /* last byte is zero */ 127 break; 128 } 129 return cnt; 130 } 131 132 #undef do_strlen_byte 133 #undef do_strlen_word 134 135 #if SMOKE_TEST_MIPS_STRLEN 136 #include <stdio.h> 137 char str1[] = "DHRYSTONE PROGRAM, 1'ST STRING"; 138 char str2[] = "DHRYSTONE PROGRAM, 2'ST STRING"; 139 140 char str3[] = "another string"; 141 char str4[] = "another"; 142 143 char str5[] = "somes tring"; 144 char str6[] = "somes_tring"; 145 146 char str7[16], str8[16]; 147 148 static char * 149 chk (unsigned long mine, unsigned long libs, int *errors) 150 { 151 static char answer[1024]; 152 char *result = mine == libs ? "PASS" : "FAIL"; 153 sprintf (answer, "new_strlen=%d: lib_strlen=%d: %s!", mine, libs, result); 154 if (mine != libs) 155 (*errors)++; 156 return answer; 157 } 158 159 int 160 main (int argc, char **argv) 161 { 162 int errors = 0; 163 /* set -1 in one position */ 164 str6[5] = 0xff; 165 /* set zero in same position with junk in following 3 */ 166 str7[0] = str8[0] = 0; 167 str7[1] = 0xff; 168 str7[2] = 'a'; 169 str7[3] = 2; 170 str8[1] = 's'; 171 str8[2] = -2; 172 str8[3] = 0; 173 174 fprintf (stderr, "========== mips_strlen%s test...\n", 175 argv[0] ? argv[0] : "unknown strlen"); 176 #define P(__x,__y) {\ 177 int a = my_strlen(__x + __y);\ 178 int b = (strlen)(__x + __y) /* library version */;\ 179 fprintf(stderr,"%s+%d: %s\n",#__x,__y,chk(a,b,&errors));\ 180 } 181 182 P (str1, 0); 183 P (str1, 1); 184 P (str1, 2); 185 P (str1, 3); 186 187 P (str2, 0); 188 P (str2, 1); 189 P (str2, 2); 190 P (str2, 3); 191 192 P (str3, 0); 193 P (str3, 1); 194 P (str3, 2); 195 P (str3, 3); 196 197 P (str4, 0); 198 P (str4, 1); 199 P (str4, 2); 200 P (str4, 3); 201 202 P (str5, 0); 203 P (str5, 1); 204 P (str5, 2); 205 P (str5, 3); 206 207 P (str6, 0); 208 P (str6, 1); 209 P (str6, 2); 210 P (str6, 3); 211 212 P (str7, 0); 213 P (str7, 1); 214 P (str7, 2); 215 P (str7, 3); 216 217 P (str8, 0); 218 P (str8, 1); 219 P (str8, 2); 220 P (str8, 3); 221 222 return errors; 223 } 224 #endif 225