memmove.S 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /* Optimized version of the standard memmove() function.
  2. This file is part of the GNU C Library.
  3. Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
  4. Contributed by Dan Pop <Dan.Pop@cern.ch>.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, write to the Free
  15. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  16. 02111-1307 USA. */
  17. /* Return: dest
  18. Inputs:
  19. in0: dest
  20. in1: src
  21. in2: byte count
  22. The core of the function is the memcpy implementation used in memcpy.S.
  23. When bytes have to be copied backwards, only the easy case, when
  24. all arguments are multiples of 8, is optimised.
  25. In this form, it assumes little endian mode. For big endian mode,
  26. sh1 must be computed using an extra instruction: sub sh1 = 64, sh1
  27. or the UM.be bit should be cleared at the beginning and set at the end. */
  28. #include "sysdep.h"
  29. #undef ret
  30. #define OP_T_THRES 16
  31. #define OPSIZ 8
  32. #define adest r15
  33. #define saved_pr r17
  34. #define saved_lc r18
  35. #define dest r19
  36. #define src r20
  37. #define len r21
  38. #define asrc r22
  39. #define tmp2 r23
  40. #define tmp3 r24
  41. #define tmp4 r25
  42. #define ptable r26
  43. #define ploop56 r27
  44. #define loopaddr r28
  45. #define sh1 r29
  46. #define loopcnt r30
  47. #define value r31
  48. #ifdef GAS_ALIGN_BREAKS_UNWIND_INFO
  49. # define ALIGN(n) { nop 0 }
  50. #else
  51. # define ALIGN(n) .align n
  52. #endif
  53. #define LOOP(shift) \
  54. ALIGN(32); \
  55. .loop##shift##: \
  56. (p[0]) ld8 r[0] = [asrc], 8 ; /* w1 */ \
  57. (p[MEMLAT+1]) st8 [dest] = value, 8 ; \
  58. (p[MEMLAT]) shrp value = r[MEMLAT], r[MEMLAT+1], shift ; \
  59. nop.b 0 ; \
  60. nop.b 0 ; \
  61. br.ctop.sptk .loop##shift ; \
  62. br.cond.sptk .cpyfew ; /* deal with the remaining bytes */
  63. #define MEMLAT 21
  64. #define Nrot (((2*MEMLAT+3) + 7) & ~7)
  65. ENTRY(memmove)
  66. .prologue
  67. alloc r2 = ar.pfs, 3, Nrot - 3, 0, Nrot
  68. .rotr r[MEMLAT + 2], q[MEMLAT + 1]
  69. .rotp p[MEMLAT + 2]
  70. mov ret0 = in0 // return value = dest
  71. .save pr, saved_pr
  72. mov saved_pr = pr // save the predicate registers
  73. .save ar.lc, saved_lc
  74. mov saved_lc = ar.lc // save the loop counter
  75. .body
  76. or tmp3 = in0, in1 ;; // tmp3 = dest | src
  77. or tmp3 = tmp3, in2 // tmp3 = dest | src | len
  78. mov dest = in0 // dest
  79. mov src = in1 // src
  80. mov len = in2 // len
  81. sub tmp2 = r0, in0 // tmp2 = -dest
  82. cmp.eq p6, p0 = in2, r0 // if (len == 0)
  83. (p6) br.cond.spnt .restore_and_exit;;// return dest;
  84. and tmp4 = 7, tmp3 // tmp4 = (dest | src | len) & 7
  85. cmp.le p6, p0 = dest, src // if dest <= src it's always safe
  86. (p6) br.cond.spnt .forward // to copy forward
  87. add tmp3 = src, len;;
  88. cmp.lt p6, p0 = dest, tmp3 // if dest > src && dest < src + len
  89. (p6) br.cond.spnt .backward // we have to copy backward
  90. .forward:
  91. shr.u loopcnt = len, 4 ;; // loopcnt = len / 16
  92. cmp.ne p6, p0 = tmp4, r0 // if ((dest | src | len) & 7 != 0)
  93. (p6) br.cond.sptk .next // goto next;
  94. // The optimal case, when dest, src and len are all multiples of 8
  95. and tmp3 = 0xf, len
  96. mov pr.rot = 1 << 16 // set rotating predicates
  97. mov ar.ec = MEMLAT + 1 ;; // set the epilog counter
  98. cmp.ne p6, p0 = tmp3, r0 // do we have to copy an extra word?
  99. adds loopcnt = -1, loopcnt;; // --loopcnt
  100. (p6) ld8 value = [src], 8;;
  101. (p6) st8 [dest] = value, 8 // copy the "odd" word
  102. mov ar.lc = loopcnt // set the loop counter
  103. cmp.eq p6, p0 = 8, len
  104. (p6) br.cond.spnt .restore_and_exit;;// the one-word special case
  105. adds adest = 8, dest // set adest one word ahead of dest
  106. adds asrc = 8, src ;; // set asrc one word ahead of src
  107. nop.b 0 // get the "golden" alignment for
  108. nop.b 0 // the next loop
  109. .l0:
  110. (p[0]) ld8 r[0] = [src], 16
  111. (p[0]) ld8 q[0] = [asrc], 16
  112. (p[MEMLAT]) st8 [dest] = r[MEMLAT], 16
  113. (p[MEMLAT]) st8 [adest] = q[MEMLAT], 16
  114. br.ctop.dptk .l0 ;;
  115. mov pr = saved_pr, -1 // restore the predicate registers
  116. mov ar.lc = saved_lc // restore the loop counter
  117. br.ret.sptk.many b0
  118. .next:
  119. cmp.ge p6, p0 = OP_T_THRES, len // is len <= OP_T_THRES
  120. and loopcnt = 7, tmp2 // loopcnt = -dest % 8
  121. (p6) br.cond.spnt .cpyfew // copy byte by byte
  122. ;;
  123. cmp.eq p6, p0 = loopcnt, r0
  124. (p6) br.cond.sptk .dest_aligned
  125. sub len = len, loopcnt // len -= -dest % 8
  126. adds loopcnt = -1, loopcnt // --loopcnt
  127. ;;
  128. mov ar.lc = loopcnt
  129. .l1: // copy -dest % 8 bytes
  130. ld1 value = [src], 1 // value = *src++
  131. ;;
  132. st1 [dest] = value, 1 // *dest++ = value
  133. br.cloop.dptk .l1
  134. .dest_aligned:
  135. and sh1 = 7, src // sh1 = src % 8
  136. and tmp2 = -8, len // tmp2 = len & -OPSIZ
  137. and asrc = -8, src // asrc = src & -OPSIZ -- align src
  138. shr.u loopcnt = len, 3 // loopcnt = len / 8
  139. and len = 7, len;; // len = len % 8
  140. adds loopcnt = -1, loopcnt // --loopcnt
  141. addl tmp4 = @ltoff(.table), gp
  142. addl tmp3 = @ltoff(.loop56), gp
  143. mov ar.ec = MEMLAT + 1 // set EC
  144. mov pr.rot = 1 << 16;; // set rotating predicates
  145. mov ar.lc = loopcnt // set LC
  146. cmp.eq p6, p0 = sh1, r0 // is the src aligned?
  147. (p6) br.cond.sptk .src_aligned
  148. add src = src, tmp2 // src += len & -OPSIZ
  149. shl sh1 = sh1, 3 // sh1 = 8 * (src % 8)
  150. ld8 ploop56 = [tmp3] // ploop56 = &loop56
  151. ld8 ptable = [tmp4];; // ptable = &table
  152. add tmp3 = ptable, sh1;; // tmp3 = &table + sh1
  153. mov ar.ec = MEMLAT + 1 + 1 // one more pass needed
  154. ld8 tmp4 = [tmp3];; // tmp4 = loop offset
  155. sub loopaddr = ploop56,tmp4 // loopadd = &loop56 - loop offset
  156. ld8 r[1] = [asrc], 8;; // w0
  157. mov b6 = loopaddr;;
  158. br b6 // jump to the appropriate loop
  159. LOOP(8)
  160. LOOP(16)
  161. LOOP(24)
  162. LOOP(32)
  163. LOOP(40)
  164. LOOP(48)
  165. LOOP(56)
  166. .src_aligned:
  167. .l3:
  168. (p[0]) ld8 r[0] = [src], 8
  169. (p[MEMLAT]) st8 [dest] = r[MEMLAT], 8
  170. br.ctop.dptk .l3
  171. .cpyfew:
  172. cmp.eq p6, p0 = len, r0 // is len == 0 ?
  173. adds len = -1, len // --len;
  174. (p6) br.cond.spnt .restore_and_exit ;;
  175. mov ar.lc = len
  176. .l4:
  177. ld1 value = [src], 1
  178. ;;
  179. st1 [dest] = value, 1
  180. br.cloop.dptk .l4 ;;
  181. .restore_and_exit:
  182. mov pr = saved_pr, -1 // restore the predicate registers
  183. mov ar.lc = saved_lc // restore the loop counter
  184. br.ret.sptk.many b0
  185. // In the case of a backward copy, optimise only the case when everything
  186. // is a multiple of 8, otherwise copy byte by byte. The backward copy is
  187. // used only when the blocks are overlapping and dest > src.
  188. .backward:
  189. shr.u loopcnt = len, 3 // loopcnt = len / 8
  190. add src = src, len // src points one byte past the end
  191. add dest = dest, len ;; // dest points one byte past the end
  192. mov ar.ec = MEMLAT + 1 // set the epilog counter
  193. mov pr.rot = 1 << 16 // set rotating predicates
  194. adds loopcnt = -1, loopcnt // --loopcnt
  195. cmp.ne p6, p0 = tmp4, r0 // if ((dest | src | len) & 7 != 0)
  196. (p6) br.cond.sptk .bytecopy ;; // copy byte by byte backward
  197. adds src = -8, src // src points to the last word
  198. adds dest = -8, dest // dest points to the last word
  199. mov ar.lc = loopcnt;; // set the loop counter
  200. .l5:
  201. (p[0]) ld8 r[0] = [src], -8
  202. (p[MEMLAT]) st8 [dest] = r[MEMLAT], -8
  203. br.ctop.dptk .l5
  204. br.cond.sptk .restore_and_exit
  205. .bytecopy:
  206. adds src = -1, src // src points to the last byte
  207. adds dest = -1, dest // dest points to the last byte
  208. adds loopcnt = -1, len;; // loopcnt = len - 1
  209. mov ar.lc = loopcnt;; // set the loop counter
  210. .l6:
  211. (p[0]) ld1 r[0] = [src], -1
  212. (p[MEMLAT]) st1 [dest] = r[MEMLAT], -1
  213. br.ctop.dptk .l6
  214. br.cond.sptk .restore_and_exit
  215. END(memmove)
  216. .rodata
  217. .align 8
  218. .table:
  219. data8 0 // dummy entry
  220. data8 .loop56 - .loop8
  221. data8 .loop56 - .loop16
  222. data8 .loop56 - .loop24
  223. data8 .loop56 - .loop32
  224. data8 .loop56 - .loop40
  225. data8 .loop56 - .loop48
  226. data8 .loop56 - .loop56
  227. libc_hidden_def (memmove)