1 /* Copyright (c) 2017  SiFive Inc. All rights reserved.
2 
3    This copyrighted material is made available to anyone wishing to use,
4    modify, copy, or redistribute it subject to the terms and conditions
5    of the FreeBSD License.   This program is distributed in the hope that
6    it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
7    including the implied warranties of MERCHANTABILITY or FITNESS FOR
8    A PARTICULAR PURPOSE.  A copy of this license is available at
9    http://www.opensource.org/licenses.
10 */
11 
12 #include <picolibc.h>
13 
14 #include <string.h>
15 #include <stdint.h>
16 #include "local.h"
17 
strlen(const char * str)18 size_t strlen(const char *str)
19 {
20   const char *start = str;
21 
22 #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
23   while (*str++)
24     ;
25   return str - start - 1;
26 #else
27   if (__builtin_expect ((uintptr_t)str & (sizeof (long) - 1), 0)) do
28     {
29       char ch = *str;
30       str++;
31       if (!ch)
32 	return str - start - 1;
33     } while ((uintptr_t)str & (sizeof (long) - 1));
34 
35   unsigned long *ls = (unsigned long *)str;
36   while (!__libc_detect_null (*ls++))
37     ;
38   __asm__ volatile ("" : "+r"(ls)); /* prevent "optimization" */
39 
40   str = (const char *)ls;
41   size_t ret = str - start, sl = sizeof (long);
42 
43   char c0 = str[0 - sl], c1 = str[1 - sl], c2 = str[2 - sl], c3 = str[3 - sl];
44   if (c0 == 0)            return ret + 0 - sl;
45   if (c1 == 0)            return ret + 1 - sl;
46   if (c2 == 0)            return ret + 2 - sl;
47   if (sl == 4 || c3 == 0) return ret + 3 - sl;
48 
49   c0 = str[4 - sl], c1 = str[5 - sl], c2 = str[6 - sl], c3 = str[7 - sl];
50   if (c0 == 0)            return ret + 4 - sl;
51   if (c1 == 0)            return ret + 5 - sl;
52   if (c2 == 0)            return ret + 6 - sl;
53 
54   return ret + 7 - sl;
55 #endif /* not PREFER_SIZE_OVER_SPEED */
56 }
57