xf.li | bfc6e71 | 2025-02-07 01:54:34 -0800 | [diff] [blame^] | 1 | /* Optimized, inlined string functions. S/390 version. |
| 2 | Copyright (C) 2000-2016 Free Software Foundation, Inc. |
| 3 | Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). |
| 4 | This file is part of the GNU C Library. |
| 5 | |
| 6 | The GNU C Library is free software; you can redistribute it and/or |
| 7 | modify it under the terms of the GNU Lesser General Public |
| 8 | License as published by the Free Software Foundation; either |
| 9 | version 2.1 of the License, or (at your option) any later version. |
| 10 | |
| 11 | The GNU C Library is distributed in the hope that it will be useful, |
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | Lesser General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU Lesser General Public |
| 17 | License along with the GNU C Library; if not, see |
| 18 | <http://www.gnu.org/licenses/>. */ |
| 19 | |
| 20 | #ifndef _STRING_H |
| 21 | # error "Never use <bits/string.h> directly; include <string.h> instead." |
| 22 | #endif |
| 23 | |
| 24 | /* Use the unaligned string inline ABI. */ |
| 25 | #define _STRING_INLINE_unaligned 1 |
| 26 | |
| 27 | /* We only provide optimizations if the user selects them and if |
| 28 | GNU CC is used. */ |
| 29 | #if !defined __NO_STRING_INLINES && defined __USE_STRING_INLINES \ |
| 30 | && defined __GNUC__ && __GNUC__ >= 2 |
| 31 | |
| 32 | #ifndef __STRING_INLINE |
| 33 | # ifndef __extern_inline |
| 34 | # define __STRING_INLINE inline |
| 35 | # else |
| 36 | # define __STRING_INLINE __extern_inline |
| 37 | # endif |
| 38 | #endif |
| 39 | |
| 40 | #define _HAVE_STRING_ARCH_strlen 1 |
| 41 | #ifndef _FORCE_INLINES |
| 42 | #define strlen(str) __strlen_g ((str)) |
| 43 | |
| 44 | __STRING_INLINE size_t __strlen_g (const char *) __asm__ ("strlen"); |
| 45 | |
| 46 | __STRING_INLINE size_t |
| 47 | __strlen_g (const char *__str) |
| 48 | { |
| 49 | char *__ptr, *__tmp; |
| 50 | |
| 51 | __ptr = (char *) 0; |
| 52 | __tmp = (char *) __str; |
| 53 | __asm__ __volatile__ (" la 0,0\n" |
| 54 | "0: srst %0,%1\n" |
| 55 | " jo 0b\n" |
| 56 | : "+&a" (__ptr), "+&a" (__tmp) : |
| 57 | : "cc", "memory", "0" ); |
| 58 | return (size_t) (__ptr - __str); |
| 59 | } |
| 60 | #endif |
| 61 | |
| 62 | /* Copy SRC to DEST. */ |
| 63 | #define _HAVE_STRING_ARCH_strcpy 1 |
| 64 | #ifndef _FORCE_INLINES |
| 65 | #define strcpy(dest, src) __strcpy_g ((dest), (src)) |
| 66 | |
| 67 | __STRING_INLINE char *__strcpy_g (char *, const char *) __asm__ ("strcpy"); |
| 68 | |
| 69 | __STRING_INLINE char * |
| 70 | __strcpy_g (char *__dest, const char *__src) |
| 71 | { |
| 72 | char *tmp = __dest; |
| 73 | |
| 74 | __asm__ __volatile__ (" la 0,0\n" |
| 75 | "0: mvst %0,%1\n" |
| 76 | " jo 0b" |
| 77 | : "+&a" (__dest), "+&a" (__src) : |
| 78 | : "cc", "memory", "0" ); |
| 79 | return tmp; |
| 80 | } |
| 81 | #endif |
| 82 | |
| 83 | #define _HAVE_STRING_ARCH_strncpy 1 |
| 84 | #ifndef _FORCE_INLINES |
| 85 | #define strncpy(dest, src, n) __strncpy_g ((dest), (src), (n)) |
| 86 | |
| 87 | __STRING_INLINE char *__strncpy_g (char *, const char *, size_t) |
| 88 | __asm__ ("strncpy"); |
| 89 | |
| 90 | __STRING_INLINE char * |
| 91 | __strncpy_g (char *__dest, const char *__src, size_t __n) |
| 92 | { |
| 93 | char *__ret = __dest; |
| 94 | char *__ptr; |
| 95 | size_t __diff; |
| 96 | |
| 97 | if (__n > 0) { |
| 98 | __diff = (size_t) (__dest - __src); |
| 99 | __ptr = (char *) __src; |
| 100 | __asm__ __volatile__ (" j 1f\n" |
| 101 | "0: la %0,1(%0)\n" |
| 102 | "1: icm 0,1,0(%0)\n" |
| 103 | " stc 0,0(%2,%0)\n" |
| 104 | " jz 3f\n" |
| 105 | #if defined(__s390x__) |
| 106 | " brctg %1,0b\n" |
| 107 | #else |
| 108 | " brct %1,0b\n" |
| 109 | #endif |
| 110 | " j 4f\n" |
| 111 | "2: la %0,1(%0)\n" |
| 112 | " stc 0,0(%2,%0)\n" |
| 113 | #if defined(__s390x__) |
| 114 | "3: brctg %1,2b\n" |
| 115 | #else |
| 116 | "3: brct %1,2b\n" |
| 117 | #endif |
| 118 | "4:" |
| 119 | : "+&a" (__ptr), "+&a" (__n) : "a" (__diff) |
| 120 | : "cc", "memory", "0" ); |
| 121 | } |
| 122 | return __ret; |
| 123 | } |
| 124 | #endif |
| 125 | |
| 126 | /* Append SRC onto DEST. */ |
| 127 | #define _HAVE_STRING_ARCH_strcat 1 |
| 128 | #ifndef _FORCE_INLINES |
| 129 | #define strcat(dest, src) __strcat_g ((dest), (src)) |
| 130 | |
| 131 | __STRING_INLINE char *__strcat_g (char *, const char *) __asm__ ("strcat"); |
| 132 | |
| 133 | __STRING_INLINE char * |
| 134 | __strcat_g (char *__dest, const char *__src) |
| 135 | { |
| 136 | char *__ret = __dest; |
| 137 | char *__ptr, *__tmp; |
| 138 | |
| 139 | /* Move __ptr to the end of __dest. */ |
| 140 | __ptr = (char *) 0; |
| 141 | __tmp = __dest; |
| 142 | __asm__ __volatile__ (" la 0,0\n" |
| 143 | "0: srst %0,%1\n" |
| 144 | " jo 0b\n" |
| 145 | : "+&a" (__ptr), "+&a" (__tmp) : |
| 146 | : "cc", "0" ); |
| 147 | |
| 148 | /* Now do the copy. */ |
| 149 | __asm__ __volatile__ (" la 0,0\n" |
| 150 | "0: mvst %0,%1\n" |
| 151 | " jo 0b" |
| 152 | : "+&a" (__ptr), "+&a" (__src) : |
| 153 | : "cc", "memory", "0" ); |
| 154 | return __ret; |
| 155 | } |
| 156 | #endif |
| 157 | |
| 158 | /* Append no more than N characters from SRC onto DEST. */ |
| 159 | #define _HAVE_STRING_ARCH_strncat 1 |
| 160 | #ifndef _FORCE_INLINES |
| 161 | #define strncat(dest, src, n) __strncat_g ((dest), (src), (n)) |
| 162 | |
| 163 | __STRING_INLINE char *__strncat_g (char *, const char *, size_t) |
| 164 | __asm__ ("strncat"); |
| 165 | |
| 166 | __STRING_INLINE char * |
| 167 | __strncat_g (char *__dest, const char *__src, size_t __n) |
| 168 | { |
| 169 | char *__ret = __dest; |
| 170 | char *__ptr, *__tmp; |
| 171 | size_t __diff; |
| 172 | |
| 173 | if (__n > 0) { |
| 174 | /* Move __ptr to the end of __dest. */ |
| 175 | __ptr = (char *) 0; |
| 176 | __tmp = __dest; |
| 177 | __asm__ __volatile__ (" la 0,0\n" |
| 178 | "0: srst %0,%1\n" |
| 179 | " jo 0b\n" |
| 180 | : "+&a" (__ptr), "+&a" (__tmp) : |
| 181 | : "cc", "memory", "0" ); |
| 182 | |
| 183 | __diff = (size_t) (__ptr - __src); |
| 184 | __tmp = (char *) __src; |
| 185 | __asm__ __volatile__ (" j 1f\n" |
| 186 | "0: la %0,1(%0)\n" |
| 187 | "1: icm 0,1,0(%0)\n" |
| 188 | " stc 0,0(%2,%0)\n" |
| 189 | " jz 2f\n" |
| 190 | #if defined(__s390x__) |
| 191 | " brctg %1,0b\n" |
| 192 | #else |
| 193 | " brct %1,0b\n" |
| 194 | #endif |
| 195 | " slr 0,0\n" |
| 196 | " stc 0,1(%2,%0)\n" |
| 197 | "2:" |
| 198 | : "+&a" (__tmp), "+&a" (__n) : "a" (__diff) |
| 199 | : "cc", "memory", "0" ); |
| 200 | |
| 201 | } |
| 202 | return __ret; |
| 203 | } |
| 204 | #endif |
| 205 | |
| 206 | /* Search N bytes of S for C. */ |
| 207 | #define _HAVE_STRING_ARCH_memchr 1 |
| 208 | #ifndef _FORCE_INLINES |
| 209 | __STRING_INLINE void * |
| 210 | memchr (const void *__str, int __c, size_t __n) |
| 211 | { |
| 212 | char *__ptr, *__tmp; |
| 213 | |
| 214 | __tmp = (char *) __str; |
| 215 | __ptr = (char *) __tmp + __n; |
| 216 | __asm__ __volatile__ (" lhi 0,0xff\n" |
| 217 | " nr 0,%2\n" |
| 218 | "0: srst %0,%1\n" |
| 219 | " jo 0b\n" |
| 220 | " brc 13,1f\n" |
| 221 | " la %0,0\n" |
| 222 | "1:" |
| 223 | : "+&a" (__ptr), "+&a" (__tmp) : "d" (__c) |
| 224 | : "cc", "memory", "0" ); |
| 225 | return __ptr; |
| 226 | } |
| 227 | #endif |
| 228 | |
| 229 | /* Compare S1 and S2. */ |
| 230 | #define _HAVE_STRING_ARCH_strcmp 1 |
| 231 | #ifndef _FORCE_INLINES |
| 232 | __STRING_INLINE int |
| 233 | strcmp (const char *__s1, const char *__s2) |
| 234 | { |
| 235 | char *__p1, *__p2; |
| 236 | int __ret; |
| 237 | |
| 238 | __p1 = (char *) __s1; |
| 239 | __p2 = (char *) __s2; |
| 240 | __asm__ __volatile__ (" slr 0,0\n" |
| 241 | "0: clst %1,%2\n" |
| 242 | " jo 0b\n" |
| 243 | " ipm %0\n" |
| 244 | " srl %0,28" |
| 245 | : "=d" (__ret), "+&a" (__p1), "+&a" (__p2) : |
| 246 | : "cc", "memory", "0" ); |
| 247 | __ret = (__ret == 0) ? 0 : (__ret == 1) ? -1 : 1; |
| 248 | return __ret; |
| 249 | } |
| 250 | #endif |
| 251 | |
| 252 | #endif /* Use string inlines && GNU CC. */ |