string.c 4.6 KB

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