Home | History | Annotate | Download | only in string
      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