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 
     37 #if !defined(UNALIGNED_INSTR_SUPPORT)
     38 /* does target have unaligned lw/ld/ualw/uald instructions? */
     39 #define UNALIGNED_INSTR_SUPPORT 0
     40 #if __mips_isa_rev < 6 && !__mips1
     41 #undef UNALIGNED_INSTR_SUPPORT
     42 #define UNALIGNED_INSTR_SUPPORT 1
     43 #endif
     44 #endif
     45 
     46 #if !defined(HW_UNALIGNED_SUPPORT)
     47 /* Does target have hardware support for unaligned accesses?  */
     48 #define HW_UNALIGNED_SUPPORT 0
     49 #if __mips_isa_rev >= 6
     50 #undef HW_UNALIGNED_SUPPORT
     51 #define HW_UNALIGNED_SUPPORT 1
     52 #endif
     53 #endif
     54 
     55 #if __mips64
     56 typedef struct
     57 {
     58   op_t B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8;
     59 } bits_t;
     60 #else
     61 typedef struct
     62 {
     63   op_t B0:8, B1:8, B2:8, B3:8;
     64 } bits_t;
     65 #endif
     66 
     67 typedef union
     68 {
     69   op_t v;
     70   bits_t b;
     71 } bitfields_t;
     72 
     73 #if !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT
     74 /* for MIPS GCC, there are no unaligned builtins - so this struct forces
     75    the compiler to treat the pointer access as unaligned.  */
     76 struct ulw
     77 {
     78   op_t uli;
     79 } __attribute__ ((packed));
     80 #endif /* !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT */
     81 
     82 #define DO_BYTE(i, ptdst) {  \
     83   *(ptdst+i) = a.b.B##i;     \
     84   if(a.b.B##i == '\0')       \
     85     return ret;              \
     86 }
     87 
     88 #if __mips64
     89 #define DO_BYTES(val, dst) {   \
     90   bitfields_t a;               \
     91   char *tdst = (char *)(dst);  \
     92   a.v = val;                   \
     93   DO_BYTE(0, tdst)             \
     94   DO_BYTE(1, tdst)             \
     95   DO_BYTE(2, tdst)             \
     96   DO_BYTE(3, tdst)             \
     97   DO_BYTE(4, tdst)             \
     98   DO_BYTE(5, tdst)             \
     99   DO_BYTE(6, tdst)             \
    100   DO_BYTE(7, tdst)             \
    101 }
    102 #else
    103 #define DO_BYTES(val, dst) {   \
    104   bitfields_t a;               \
    105   char *tdst = (char *)(dst);  \
    106   a.v = val;                   \
    107   DO_BYTE(0, tdst)             \
    108   DO_BYTE(1, tdst)             \
    109   DO_BYTE(2, tdst)             \
    110   DO_BYTE(3, tdst)             \
    111 }
    112 #endif
    113 
    114 #define DO_WORD_ALIGNED(dst, src) {                 \
    115   op_t val = *(src);                                \
    116   if ((((val - mask_1) & ~val) & mask_128) != 0) {  \
    117     DO_BYTES(val, dst);                             \
    118   } else *(dst) = val;                              \
    119 }
    120 
    121 #if !HW_UNALIGNED_SUPPORT
    122 #if UNALIGNED_INSTR_SUPPORT
    123 #define DO_WORD_UNALIGNED(dst, src) {               \
    124   op_t val = *(src);                                \
    125   if ((((val - mask_1) & ~val) & mask_128) != 0) {  \
    126     DO_BYTES(val, dst);                             \
    127   } else {                                          \
    128     struct ulw *a = (struct ulw *)(dst);            \
    129     a->uli = val;                                   \
    130   }                                                 \
    131 }
    132 #else
    133 #define DO_WORD_UNALIGNED(dst, src) {                 \
    134   op_t val = *(src);                                  \
    135   if ((((val - mask_1) & ~val) & mask_128) != 0) {    \
    136     DO_BYTES(val, dst);                               \
    137   } else {                                            \
    138     char *pdst = (char *) dst;                        \
    139     const char *psrc = (const char *) src;            \
    140     for (; (*pdst = *psrc) != '\0'; ++psrc, ++pdst);  \
    141     return ret;                                       \
    142   }                                                   \
    143 }
    144 #endif /* UNALIGNED_INSTR_SUPPORT */
    145 
    146 #define PROCESS_UNALIGNED_WORDS(a, b) { \
    147   while (1) {                           \
    148     DO_WORD_UNALIGNED(a, b);            \
    149     DO_WORD_UNALIGNED(a + 1, b + 1);    \
    150     DO_WORD_UNALIGNED(a + 2, b + 2);    \
    151     DO_WORD_UNALIGNED(a + 3, b + 3);    \
    152     a += 4;                             \
    153     b += 4;                             \
    154   }                                     \
    155 }
    156 #endif /* HW_UNALIGNED_SUPPORT */
    157 
    158 #define PROCESS_ALIGNED_WORDS(a, b) {  \
    159   while (1) {                          \
    160     DO_WORD_ALIGNED(a, b);             \
    161     DO_WORD_ALIGNED(a + 1, b + 1);     \
    162     DO_WORD_ALIGNED(a + 2, b + 2);     \
    163     DO_WORD_ALIGNED(a + 3, b + 3);     \
    164     a += 4;                            \
    165     b += 4;                            \
    166   }                                    \
    167 }
    168 
    169 char *
    170 strcpy (char *to, const char *from)
    171 {
    172   char *ret = to;
    173   op_t mask_1, mask_128;
    174   const op_t *src;
    175   op_t *dst;
    176 
    177   for (; (*to = *from) != '\0' && ((size_t) from % sizeof (op_t)) != 0; ++from, ++to);
    178 
    179   if(*to != '\0') {
    180     __asm__ volatile (
    181       "li %0, 0x01010101 \n\t"
    182       : "=r" (mask_1)
    183     );
    184 #if __mips64
    185     mask_1 |= mask_1 << 32;
    186 #endif
    187     mask_128 = mask_1 << 7;
    188 
    189     src = (const op_t *) from;
    190     dst = (op_t *) to;
    191 
    192 #if HW_UNALIGNED_SUPPORT
    193     PROCESS_ALIGNED_WORDS(dst, src);
    194 #else
    195     if (((unsigned long) dst) % sizeof (op_t) == 0) {
    196       PROCESS_ALIGNED_WORDS(dst, src);
    197     } else {
    198       PROCESS_UNALIGNED_WORDS(dst, src);
    199     }
    200 #endif
    201   }
    202 
    203   return ret;
    204 }
    205