string.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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 _GNU_SOURCE
  28. #include <string.h>
  29. #include <locale.h> /* for __LOCALE_C_ONLY */
  30. #ifdef L_memcpy
  31. void attribute_hidden *__memcpy(void *to, const void *from, size_t n)
  32. /* PPC can do pre increment and load/store, but not post increment and load/store.
  33. Therefore use *++ptr instead of *ptr++. */
  34. {
  35. unsigned long rem, chunks, tmp1, tmp2;
  36. unsigned char *tmp_to;
  37. unsigned char *tmp_from = (unsigned char *)from;
  38. chunks = n / 8;
  39. tmp_from -= 4;
  40. tmp_to = to - 4;
  41. if (!chunks)
  42. goto lessthan8;
  43. rem = (unsigned long )tmp_to % 4;
  44. if (rem)
  45. goto align;
  46. copy_chunks:
  47. do {
  48. /* make gcc to load all data, then store it */
  49. tmp1 = *(unsigned long *)(tmp_from+4);
  50. tmp_from += 8;
  51. tmp2 = *(unsigned long *)tmp_from;
  52. *(unsigned long *)(tmp_to+4) = tmp1;
  53. tmp_to += 8;
  54. *(unsigned long *)tmp_to = tmp2;
  55. } while (--chunks);
  56. lessthan8:
  57. n = n % 8;
  58. if (n >= 4) {
  59. *(unsigned long *)(tmp_to+4) = *(unsigned long *)(tmp_from+4);
  60. tmp_from += 4;
  61. tmp_to += 4;
  62. n = n-4;
  63. }
  64. if (!n ) return to;
  65. tmp_from += 3;
  66. tmp_to += 3;
  67. do {
  68. *++tmp_to = *++tmp_from;
  69. } while (--n);
  70. return to;
  71. align:
  72. rem = 4 - rem;
  73. n = n - rem;
  74. do {
  75. *(tmp_to+4) = *(tmp_from+4);
  76. ++tmp_from;
  77. ++tmp_to;
  78. } while (--rem);
  79. chunks = n / 8;
  80. if (chunks)
  81. goto copy_chunks;
  82. goto lessthan8;
  83. }
  84. strong_alias(__memcpy, memcpy);
  85. #endif
  86. #ifdef L_memmove
  87. void attribute_hidden *__memmove(void *to, const void *from, size_t n)
  88. {
  89. unsigned long rem, chunks, tmp1, tmp2;
  90. unsigned char *tmp_to;
  91. unsigned char *tmp_from = (unsigned char *)from;
  92. if (tmp_from >= (unsigned char *)to)
  93. return memcpy(to, from, n);
  94. chunks = n / 8;
  95. tmp_from += n;
  96. tmp_to = to + n;
  97. if (!chunks)
  98. goto lessthan8;
  99. rem = (unsigned long )tmp_to % 4;
  100. if (rem)
  101. goto align;
  102. copy_chunks:
  103. do {
  104. /* make gcc to load all data, then store it */
  105. tmp1 = *(unsigned long *)(tmp_from-4);
  106. tmp_from -= 8;
  107. tmp2 = *(unsigned long *)tmp_from;
  108. *(unsigned long *)(tmp_to-4) = tmp1;
  109. tmp_to -= 8;
  110. *(unsigned long *)tmp_to = tmp2;
  111. } while (--chunks);
  112. lessthan8:
  113. n = n % 8;
  114. if (n >= 4) {
  115. *(unsigned long *)(tmp_to-4) = *(unsigned long *)(tmp_from-4);
  116. tmp_from -= 4;
  117. tmp_to -= 4;
  118. n = n-4;
  119. }
  120. if (!n ) return to;
  121. do {
  122. *--tmp_to = *--tmp_from;
  123. } while (--n);
  124. return to;
  125. align:
  126. rem = 4 - rem;
  127. n = n - rem;
  128. do {
  129. *--tmp_to = *--tmp_from;
  130. } while (--rem);
  131. chunks = n / 8;
  132. if (chunks)
  133. goto copy_chunks;
  134. goto lessthan8;
  135. }
  136. strong_alias(__memmove, memmove);
  137. #endif
  138. #ifdef L_memset
  139. static inline int expand_byte_word(int c){
  140. /* this does:
  141. c = c << 8 | c;
  142. c = c << 16 | c ;
  143. */
  144. asm("rlwimi %0,%0,8,16,23\n"
  145. "\trlwimi %0,%0,16,0,15\n"
  146. : "=r" (c) : "0" (c));
  147. return c;
  148. }
  149. void attribute_hidden *__memset(void *to, int c, size_t n)
  150. {
  151. unsigned long rem, chunks;
  152. unsigned char *tmp_to;
  153. chunks = n / 8;
  154. tmp_to = to - 4;
  155. c = expand_byte_word(c);
  156. if (!chunks)
  157. goto lessthan8;
  158. rem = (unsigned long )tmp_to % 4;
  159. if (rem)
  160. goto align;
  161. copy_chunks:
  162. do {
  163. *(unsigned long *)(tmp_to+4) = c;
  164. tmp_to += 4;
  165. *(unsigned long *)(tmp_to+4) = c;
  166. tmp_to += 4;
  167. } while (--chunks);
  168. lessthan8:
  169. n = n % 8;
  170. if (n >= 4) {
  171. *(unsigned long *)(tmp_to+4) = c;
  172. tmp_to += 4;
  173. n = n-4;
  174. }
  175. if (!n ) return to;
  176. tmp_to += 3;
  177. do {
  178. *++tmp_to = c;
  179. } while (--n);
  180. return to;
  181. align:
  182. rem = 4 - rem;
  183. n = n-rem;
  184. do {
  185. *(tmp_to+4) = c;
  186. ++tmp_to;
  187. } while (--rem);
  188. chunks = n / 8;
  189. if (chunks)
  190. goto copy_chunks;
  191. goto lessthan8;
  192. }
  193. strong_alias(__memset, memset);
  194. #endif
  195. #ifdef L_bzero
  196. weak_alias(__bzero,bzero);
  197. void __bzero(void *s, size_t n)
  198. {
  199. (void)memset(s, 0, n);
  200. }
  201. #endif