source: trunk/libs/newlib/src/newlib/libc/machine/mips/strncpy.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 6.0 KB
Line 
1/*
2 * strncpy.S -- strncmp function.  On at least some MIPS chips, you get better
3 * code by hand unrolling the loops, and by using store words to zero the
4 * remainder of the buffer than the default newlib C version.
5 *
6 * Copyright (c) 2001 Red Hat, Inc.
7 *
8 * The authors hereby grant permission to use, copy, modify, distribute,
9 * and license this software and its documentation for any purpose, provided
10 * that existing copyright notices are retained in all copies and that this
11 * notice is included verbatim in any distributions. No written agreement,
12 * license, or royalty fee is required for any of the authorized uses.
13 * Modifications to this software may be copyrighted by their authors
14 * and need not follow the licensing terms described here, provided that
15 * the new terms are clearly indicated on the first page of each file where
16 * they apply.  */
17
18#include <string.h>
19#include <stddef.h>
20#include <stdlib.h>
21#include <stdint.h>
22
23#if !defined(__GNUC__) || (__GNUC__ < 3)
24#define __builtin_expect(a,b) a
25
26#else
27#ifdef __mips64
28/* Don't use limits test for the size of long, in order to allow the use of
29   64-bit stores on MIPS3 machines, even if -mlong32 was used.  */
30typedef unsigned word_type __attribute__ ((mode (DI)));
31#else
32typedef unsigned word_type __attribute__ ((mode (SI)));
33#endif
34
35typedef unsigned si_type __attribute__ ((mode (SI)));
36typedef unsigned hi_type __attribute__ ((mode (HI)));
37
38#ifndef UNROLL_FACTOR
39#define UNROLL_FACTOR 4
40
41#elif (UNROLL_FACTOR != 2) && (UNROLL_FACTOR != 4)
42#error "UNROLL_FACTOR must be 2 or 4"
43#endif
44#endif
45
46char *
47strncpy (char *dst0, const char *src0, size_t count)
48{
49#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || defined(__mips16) || !defined(__GNUC__) || (__GNUC__ < 3)
50  char *dst, *end;
51  const char *src;
52  int ch;
53
54  dst = dst0;
55  src = src0;
56  end = dst + count;
57  while (dst != end)
58    {
59      *dst++ = ch = *src++;
60      if (__builtin_expect (ch == '\0', 0))
61        {
62          while (dst != end)
63            *dst++ = '\0';
64
65          break;
66        }
67    }
68
69  return dst0;
70
71#else
72  unsigned char *dst;
73  unsigned char *dst_end;
74  unsigned char *end;
75  const unsigned char *src;
76  int ch0, ch1;
77#if UNROLL_FACTOR > 2
78  int ch2, ch3;
79#endif
80  int ch;
81  int odd_bytes;
82  size_t long_count;
83
84  dst = (unsigned char *)dst0;
85  src = (unsigned const char *)src0;
86  /* Take care of any odd bytes in the source data because we
87   * want to unroll where we read ahead 2 or 4 bytes at a time and then
88   * check each byte for the null terminator.  This can result in
89   * a segfault for the case where the source pointer is unaligned,
90   * the null terminator is in valid memory, but reading 2 or 4 bytes at a
91   * time blindly eventually goes outside of valid memory. */
92  while (((uintptr_t) src & (UNROLL_FACTOR - 1)) != 0 && count > 0)
93    {
94      *dst++ = ch = *src++;
95      --count;
96      if (ch == '\0')
97        {
98          end = dst + count;
99          while (dst != end)
100            *dst++ = '\0';
101
102          return dst0;
103        }
104    }
105
106  if (__builtin_expect (count >= 4, 1))
107    {
108      odd_bytes = (count & (UNROLL_FACTOR - 1));
109      count -= odd_bytes;
110
111      do
112        {
113          ch0 = src[0];
114          ch1 = src[1];
115#if UNROLL_FACTOR > 2
116          ch2 = src[2];
117          ch3 = src[3];
118#endif
119          src += UNROLL_FACTOR;
120          count -= UNROLL_FACTOR;
121
122          dst[0] = ch0;
123          if (ch0 == '\0')
124            goto found_null0;
125
126          dst[1] = ch1;
127          if (ch1 == '\0')
128            goto found_null1;
129
130#if UNROLL_FACTOR > 2
131          dst[2] = ch2;
132          if (ch2 == '\0')
133            goto found_null2;
134
135          dst[3] = ch3;
136          if (ch3 == '\0')
137            goto found_null3;
138#endif
139
140          dst += UNROLL_FACTOR;
141        }
142      while (count);
143
144      /* fall through, count == 0, no null found, deal with last bytes */
145      count = odd_bytes;
146    }
147
148  end = dst + count;
149  while (dst != end)
150    {
151      *dst++ = ch = *src++;
152      if (ch == '\0')
153        {
154          while (dst != end)
155            *dst++ = '\0';
156
157          break;
158        }
159    }
160
161  return dst0;
162
163  /* Found null byte in first byte, count has been decremented by 4, null has
164     been stored in dst[0].  */
165 found_null0:
166  count++;                      /* add 1 to cover remaining byte */
167  dst -= 1;                     /* adjust dst += 4 gets correct ptr */
168  /* fall through */
169
170  /* Found null byte in second byte, count has been decremented by 4, null has
171     been stored in dst[1].  */
172 found_null1:
173#if UNROLL_FACTOR > 2
174  count++;                      /* add 1 to cover remaining byte */
175  dst -= 1;                     /* adjust dst += 4 gets correct ptr */
176  /* fall through */
177
178  /* Found null byte in third byte, count has been decremented by 4, null has
179     been stored in dst[2].  */
180 found_null2:
181  count++;                      /* add 1 to cover remaining byte */
182  dst -= 1;                     /* adjust dst += 4 gets correct ptr */
183  /* fall through */
184
185  /* Found null byte in fourth byte, count is accurate, dst has not been
186     updated yet.  */
187 found_null3:
188#endif
189  count += odd_bytes;           /* restore odd byte count */
190  dst += UNROLL_FACTOR;
191
192  /* Zero fill remainder of the array.  Unroll the loop, and use word/dword
193     stores where we can.  */
194  while (count && (((long)dst) & (sizeof (word_type) - 1)) != 0)
195    {
196      count--;
197      *dst++ = 0;
198    }
199
200  while (count >= UNROLL_FACTOR*sizeof (word_type))
201    {
202      count -= UNROLL_FACTOR*sizeof (word_type);
203      dst += UNROLL_FACTOR*sizeof (word_type);
204#if UNROLL_FACTOR > 2
205      ((word_type *)(void *)dst)[-4] = 0;
206      ((word_type *)(void *)dst)[-3] = 0;
207#endif
208      ((word_type *)(void *)dst)[-2] = 0;
209      ((word_type *)(void *)dst)[-1] = 0;
210    }
211
212#if UNROLL_FACTOR > 2
213  if (count >= 2*sizeof (word_type))
214    {
215      count -= 2*sizeof (word_type);
216      ((word_type *)(void *)dst)[0] = 0;
217      ((word_type *)(void *)dst)[1] = 0;
218      dst += 2*sizeof (word_type);
219    }
220#endif
221
222  if (count >= sizeof (word_type))
223    {
224      count -= sizeof (word_type);
225      ((word_type *)(void *)dst)[0] = 0;
226      dst += sizeof (word_type);
227    }
228
229#ifdef __mips64
230  if (count >= sizeof (si_type))
231    {
232      count -= sizeof (si_type);
233      ((si_type *)(void *)dst)[0] = 0;
234      dst += sizeof (si_type);
235    }
236#endif
237
238  if (count >= sizeof (hi_type))
239    {
240      count -= sizeof (hi_type);
241      ((hi_type *)(void *)dst)[0] = 0;
242      dst += sizeof (hi_type);
243    }
244
245  if (count)
246    *dst = '\0';
247
248  return dst0;
249#endif
250}
Note: See TracBrowser for help on using the repository browser.