OSDN Git Service

Fic gcc 4.0 compilation. Still no confimation that this works on
[uclinux-h8/uClibc.git] / libc / string / powerpc / string.c
1 /*
2  * This program is free software; you can redistribute it and/or modify it under
3  * the terms of the GNU Library General Public License as published by the Free
4  * Software Foundation; either version 2 of the License, or (at your option) any
5  * later version.
6  *
7  * This program is distributed in the hope that it will be useful, but WITHOUT
8  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9  * FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
10  * details.
11  */
12
13 /* These are carefully optimized mem*() functions for PPC written in C.
14  * Don't muck around with these function without checking the generated
15  * assmbler code.
16  * It is possible to optimize these significantly more by using specific
17  * data cache instructions(mainly dcbz). However that requires knownledge
18  * about the CPU's cache line size.
19  *
20  * BUG ALERT!
21  * The cache instructions on MPC8xx CPU's are buggy(they don't update
22  * the DAR register when causing a DTLB Miss/Error) and cannot be
23  * used on 8xx CPU's without a kernel patch to work around this
24  * problem.
25  *   
26  * Copyright (C) 2004 Joakim Tjernlund
27  */
28
29 #define _STDIO_UTILITY
30 #define _GNU_SOURCE
31 #include <string.h>
32 #include <locale.h> /* for __LOCALE_C_ONLY */
33
34 #ifdef L_memcpy
35 void attribute_hidden *__memcpy(void *to, const void *from, size_t n)
36 /* PPC can do pre increment and load/store, but not post increment and load/store.
37    Therefore use *++ptr instead of *ptr++. */
38 {
39         unsigned long rem, chunks, tmp1, tmp2;
40         unsigned char *tmp_to;
41         unsigned char *tmp_from = (unsigned char *)from;
42
43         chunks = n / 8;
44         tmp_from -= 4;
45         tmp_to = to - 4;
46         if (!chunks)
47                 goto lessthan8;
48         rem = (unsigned long )tmp_to % 4;
49         if (rem)
50                 goto align;
51  copy_chunks:
52         do {
53                 /* make gcc to load all data, then store it */
54                 tmp1 = *(unsigned long *)(tmp_from+4);
55                 tmp_from += 8;
56                 tmp2 = *(unsigned long *)tmp_from;
57                 *(unsigned long *)(tmp_to+4) = tmp1;
58                 tmp_to += 8;
59                 *(unsigned long *)tmp_to = tmp2;
60         } while (--chunks);
61  lessthan8:
62         n = n % 8;
63         if (n >= 4) {
64                 *(unsigned long *)(tmp_to+4) = *(unsigned long *)(tmp_from+4);
65                 tmp_from += 4;
66                 tmp_to += 4;
67                 n = n-4;
68         }
69         if (!n ) return to;
70         tmp_from += 3;
71         tmp_to += 3;
72         do {
73                 *++tmp_to = *++tmp_from;
74         } while (--n);
75         
76         return to;
77  align:
78         rem = 4 - rem;
79         n = n - rem;
80         do {
81                 *(tmp_to+4) = *(tmp_from+4);
82                 ++tmp_from;
83                 ++tmp_to;
84         } while (--rem);
85         chunks = n / 8;
86         if (chunks)
87                 goto copy_chunks;
88         goto lessthan8;
89 }
90 strong_alias(__memcpy, memcpy);
91 #endif
92
93 #ifdef L_memmove
94 void attribute_hidden *__memmove(void *to, const void *from, size_t n)
95 {
96         unsigned long rem, chunks, tmp1, tmp2;
97         unsigned char *tmp_to;
98         unsigned char *tmp_from = (unsigned char *)from;
99
100         if (tmp_from >= (unsigned char *)to)
101                 return memcpy(to, from, n);
102         chunks = n / 8;
103         tmp_from += n;
104         tmp_to = to + n;
105         if (!chunks)
106                 goto lessthan8;
107         rem = (unsigned long )tmp_to % 4;
108         if (rem)
109                 goto align;
110  copy_chunks:
111         do {
112                 /* make gcc to load all data, then store it */
113                 tmp1 = *(unsigned long *)(tmp_from-4);
114                 tmp_from -= 8;
115                 tmp2 = *(unsigned long *)tmp_from;
116                 *(unsigned long *)(tmp_to-4) = tmp1;
117                 tmp_to -= 8;
118                 *(unsigned long *)tmp_to = tmp2;
119         } while (--chunks);
120  lessthan8:
121         n = n % 8;
122         if (n >= 4) {
123                 *(unsigned long *)(tmp_to-4) = *(unsigned long *)(tmp_from-4);
124                 tmp_from -= 4;
125                 tmp_to -= 4;
126                 n = n-4;
127         }
128         if (!n ) return to;
129         do {
130                 *--tmp_to = *--tmp_from;
131         } while (--n);
132         
133         return to;
134  align:
135         rem = 4 - rem;
136         n = n - rem;
137         do {
138                 *--tmp_to = *--tmp_from;
139         } while (--rem);
140         chunks = n / 8;
141         if (chunks)
142                 goto copy_chunks;
143         goto lessthan8;
144 }
145 strong_alias(__memmove, memmove);
146 #endif
147
148 #ifdef L_memset
149 static inline int expand_byte_word(int c){
150         /* this does: 
151            c = c << 8 | c;
152            c = c << 16 | c ;
153         */
154         asm("rlwimi     %0,%0,8,16,23\n"
155             "\trlwimi   %0,%0,16,0,15\n"
156             : "=r" (c) : "0" (c));
157         return c;
158 }
159 void attribute_hidden *__memset(void *to, int c, size_t n)
160 {
161         unsigned long rem, chunks;
162         unsigned char *tmp_to;
163
164         chunks = n / 8;
165         tmp_to = to - 4;
166         c = expand_byte_word(c);
167         if (!chunks)
168                 goto lessthan8;
169         rem = (unsigned long )tmp_to % 4;
170         if (rem)
171                 goto align;
172  copy_chunks:
173         do {
174                 *(unsigned long *)(tmp_to+4) = c;
175                 tmp_to += 4;
176                 *(unsigned long *)(tmp_to+4) = c;
177                 tmp_to += 4;
178         } while (--chunks);
179  lessthan8:
180         n = n % 8;
181         if (n >= 4) {
182                 *(unsigned long *)(tmp_to+4) = c;
183                 tmp_to += 4;
184                 n = n-4;
185         }
186         if (!n ) return to;
187         tmp_to += 3;
188         do {
189                 *++tmp_to = c;
190         } while (--n);
191         
192         return to;
193  align:
194         rem = 4 - rem;
195         n = n-rem;
196         do {
197                 *(tmp_to+4) = c;
198                 ++tmp_to;
199         } while (--rem);
200         chunks = n / 8;
201         if (chunks)
202                 goto copy_chunks;
203         goto lessthan8;
204 }
205 strong_alias(__memset, memset);
206 #endif
207
208 #ifdef L_bzero
209 weak_alias(__bzero,bzero);
210 void __bzero(void *s, size_t n)
211 {
212         (void)memset(s, 0, n);
213 }
214 #endif