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
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
13 /* These are carefully optimized mem*() functions for PPC written in C.
14 * Don't muck around with these function without checking the generated
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.
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
26 * Copyright (C) 2004 Joakim Tjernlund
29 #define _STDIO_UTILITY
32 #include <locale.h> /* for __LOCALE_C_ONLY */
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++. */
39 unsigned long rem, chunks, tmp1, tmp2;
40 unsigned char *tmp_to;
41 unsigned char *tmp_from = (unsigned char *)from;
48 rem = (unsigned long )tmp_to % 4;
53 /* make gcc to load all data, then store it */
54 tmp1 = *(unsigned long *)(tmp_from+4);
56 tmp2 = *(unsigned long *)tmp_from;
57 *(unsigned long *)(tmp_to+4) = tmp1;
59 *(unsigned long *)tmp_to = tmp2;
64 *(unsigned long *)(tmp_to+4) = *(unsigned long *)(tmp_from+4);
73 *++tmp_to = *++tmp_from;
81 *(tmp_to+4) = *(tmp_from+4);
90 strong_alias(__memcpy, memcpy);
94 void attribute_hidden *__memmove(void *to, const void *from, size_t n)
96 unsigned long rem, chunks, tmp1, tmp2;
97 unsigned char *tmp_to;
98 unsigned char *tmp_from = (unsigned char *)from;
100 if (tmp_from >= (unsigned char *)to)
101 return memcpy(to, from, n);
107 rem = (unsigned long )tmp_to % 4;
112 /* make gcc to load all data, then store it */
113 tmp1 = *(unsigned long *)(tmp_from-4);
115 tmp2 = *(unsigned long *)tmp_from;
116 *(unsigned long *)(tmp_to-4) = tmp1;
118 *(unsigned long *)tmp_to = tmp2;
123 *(unsigned long *)(tmp_to-4) = *(unsigned long *)(tmp_from-4);
130 *--tmp_to = *--tmp_from;
138 *--tmp_to = *--tmp_from;
145 strong_alias(__memmove, memmove);
149 static inline int expand_byte_word(int c){
154 asm("rlwimi %0,%0,8,16,23\n"
155 "\trlwimi %0,%0,16,0,15\n"
156 : "=r" (c) : "0" (c));
159 void attribute_hidden *__memset(void *to, int c, size_t n)
161 unsigned long rem, chunks;
162 unsigned char *tmp_to;
166 c = expand_byte_word(c);
169 rem = (unsigned long )tmp_to % 4;
174 *(unsigned long *)(tmp_to+4) = c;
176 *(unsigned long *)(tmp_to+4) = c;
182 *(unsigned long *)(tmp_to+4) = c;
205 strong_alias(__memset, memset);
209 weak_alias(__bzero,bzero);
210 void __bzero(void *s, size_t n)
212 (void)memset(s, 0, n);