Home | History | Annotate | Download | only in string
      1 /*
      2  * Copyright (c) 2017 Imagination Technologies.
      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 Imagination Technologies 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 
     35 #define op_t        unsigned long int
     36 #define op_size     sizeof (op_t)
     37 
     38 #if __mips64 || __mips_isa_rev >= 2
     39 static inline size_t __attribute__ ((always_inline))
     40 do_bytes (const char *base, const char *p, op_t inval)
     41 {
     42   op_t outval = 0;
     43 #if __mips64
     44   __asm__ volatile (
     45     "dsbh %1, %0 \n\t"
     46     "dshd %0, %1 \n\t"
     47     "dclz %1, %0 \n\t"
     48     : "+r" (inval), "+r" (outval)
     49   );
     50 #else
     51   __asm__ volatile (
     52     "wsbh %1, %0 \n\t"
     53     "rotr %0, %1, 16 \n\t"
     54     "clz %1, %0 \n\t"
     55     : "+r" (inval), "+r" (outval)
     56   );
     57 #endif
     58   p += (outval >> 3);
     59   return (size_t) (p - base);
     60 }
     61 
     62 #define DO_WORD(w, cnt) {                                \
     63   op_t val = ((w[cnt] - mask_1) & ~w[cnt]) & mask_128;   \
     64   if (val)                                               \
     65     return do_bytes(str, (const char *)(w + cnt), val);  \
     66 }
     67 #else
     68 static inline size_t __attribute__ ((always_inline))
     69 do_bytes (const char *base, const char *p)
     70 {
     71   for (; *p; ++p);
     72   return (size_t) (p - base);
     73 }
     74 
     75 #define DO_WORD(w, cnt) {                           \
     76   if (((w[cnt] - mask_1) & ~w[cnt]) & mask_128)     \
     77     return do_bytes(str, (const char *)(w + cnt));  \
     78 }
     79 #endif
     80 
     81 size_t
     82 strlen (const char *str)
     83 {
     84   if (*str) {
     85     const char *p = (const char *) str;
     86     const op_t *w;
     87     op_t mask_1, mask_128;
     88 
     89     while ((size_t) p % sizeof (op_t)) {
     90       if (!(*p))
     91         return (p - str);
     92       p++;
     93     }
     94 
     95     __asm__ volatile (
     96       "li %0, 0x01010101 \n\t"
     97       : "=r" (mask_1)
     98     );
     99 #if __mips64
    100     mask_1 |= mask_1 << 32;
    101 #endif
    102     mask_128 = mask_1 << 7;
    103 
    104     w = (const op_t *) p;
    105 
    106     while (1) {
    107       DO_WORD(w, 0);
    108       DO_WORD(w, 1);
    109       DO_WORD(w, 2);
    110       DO_WORD(w, 3);
    111       w += 4;
    112     }
    113   }
    114   return 0;
    115 }
    116