memcpy.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *
  3.  * Optimized version of the standard memcpy() function
  4.  *
  5.  * Inputs:
  6.  *  in0: destination address
  7.  * in1: source address
  8.  * in2: number of bytes to copy
  9.  * Output:
  10.  *  no return value
  11.  *
  12.  * Copyright (C) 2000-2001 Hewlett-Packard Co
  13.  * Stephane Eranian <eranian@hpl.hp.com>
  14.  * David Mosberger-Tang <davidm@hpl.hp.com>
  15.  */
  16. #include <linux/config.h>
  17. #include <asm/asmmacro.h>
  18. GLOBAL_ENTRY(bcopy)
  19. .regstk 3,0,0,0
  20. mov r8=in0
  21. mov in0=in1
  22. ;;
  23. mov in1=r8
  24. // gas doesn't handle control flow across procedures, so it doesn't
  25. // realize that a stop bit is needed before the "alloc" instruction
  26. // below
  27. {
  28. nop.m 0
  29. nop.f 0
  30. nop.i 0
  31. } ;;
  32. END(bcopy)
  33. // FALL THROUGH
  34. GLOBAL_ENTRY(memcpy)
  35. # define MEM_LAT 21 /* latency to memory */
  36. # define dst r2
  37. # define src r3
  38. # define retval r8
  39. # define saved_pfs r9
  40. # define saved_lc r10
  41. # define saved_pr r11
  42. # define cnt r16
  43. # define src2 r17
  44. # define t0 r18
  45. # define t1 r19
  46. # define t2 r20
  47. # define t3 r21
  48. # define t4 r22
  49. # define src_end r23
  50. # define N (MEM_LAT + 4)
  51. # define Nrot ((N + 7) & ~7)
  52. /*
  53.  * First, check if everything (src, dst, len) is a multiple of eight.  If
  54.  * so, we handle everything with no taken branches (other than the loop
  55.  * itself) and a small icache footprint.  Otherwise, we jump off to
  56.  * the more general copy routine handling arbitrary
  57.  * sizes/alignment etc.
  58.  */
  59. .prologue
  60. .save ar.pfs, saved_pfs
  61. alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot
  62. .save ar.lc, saved_lc
  63. mov saved_lc=ar.lc
  64. or t0=in0,in1
  65. ;;
  66. or t0=t0,in2
  67. .save pr, saved_pr
  68. mov saved_pr=pr
  69. .body
  70. cmp.eq p6,p0=in2,r0 // zero length?
  71. mov retval=in0 // return dst
  72. (p6) br.ret.spnt.many rp // zero length, return immediately
  73. ;;
  74. mov dst=in0 // copy because of rotation
  75. shr.u cnt=in2,3 // number of 8-byte words to copy
  76. mov pr.rot=1<<16
  77. ;;
  78. adds cnt=-1,cnt // br.ctop is repeat/until
  79. cmp.gtu p7,p0=16,in2 // copying less than 16 bytes?
  80. mov ar.ec=N
  81. ;;
  82. and t0=0x7,t0
  83. mov ar.lc=cnt
  84. ;;
  85. cmp.ne p6,p0=t0,r0
  86. mov src=in1 // copy because of rotation
  87. (p7) br.cond.spnt.few .memcpy_short
  88. (p6) br.cond.spnt.few .memcpy_long
  89. ;;
  90. nop.m 0
  91. ;;
  92. nop.m 0
  93. nop.i 0
  94. ;;
  95. nop.m 0
  96. ;;
  97. .rotr val[N]
  98. .rotp p[N]
  99. .align 32
  100. 1: { .mib
  101. (p[0]) ld8 val[0]=[src],8
  102. nop.i 0
  103. brp.loop.imp 1b, 2f
  104. }
  105. 2: { .mfb
  106. (p[N-1])st8 [dst]=val[N-1],8
  107. nop.f 0
  108. br.ctop.dptk.few 1b
  109. }
  110. ;;
  111. mov ar.lc=saved_lc
  112. mov pr=saved_pr,-1
  113. mov ar.pfs=saved_pfs
  114. br.ret.sptk.many rp
  115. /*
  116.  * Small (<16 bytes) unaligned copying is done via a simple byte-at-the-time
  117.  * copy loop.  This performs relatively poorly on Itanium, but it doesn't
  118.  * get used very often (gcc inlines small copies) and due to atomicity
  119.  * issues, we want to avoid read-modify-write of entire words.
  120.  */
  121. .align 32
  122. .memcpy_short:
  123. adds cnt=-1,in2 // br.ctop is repeat/until
  124. mov ar.ec=MEM_LAT
  125. brp.loop.imp 1f, 2f
  126. ;;
  127. mov ar.lc=cnt
  128. ;;
  129. nop.m 0
  130. ;;
  131. nop.m 0
  132. nop.i 0
  133. ;;
  134. nop.m 0
  135. ;;
  136. nop.m 0
  137. ;;
  138. /*
  139.  * It is faster to put a stop bit in the loop here because it makes
  140.  * the pipeline shorter (and latency is what matters on short copies).
  141.  */
  142. .align 32
  143. 1: { .mib
  144. (p[0]) ld1 val[0]=[src],1
  145. nop.i 0
  146. brp.loop.imp 1b, 2f
  147. } ;;
  148. 2: { .mfb
  149. (p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1
  150. nop.f 0
  151. br.ctop.dptk.few 1b
  152. } ;;
  153. mov ar.lc=saved_lc
  154. mov pr=saved_pr,-1
  155. mov ar.pfs=saved_pfs
  156. br.ret.sptk.many rp
  157. /*
  158.  * Large (>= 16 bytes) copying is done in a fancy way.  Latency isn't
  159.  * an overriding concern here, but throughput is.  We first do
  160.  * sub-word copying until the destination is aligned, then we check
  161.  * if the source is also aligned.  If so, we do a simple load/store-loop
  162.  * until there are less than 8 bytes left over and then we do the tail,
  163.  * by storing the last few bytes using sub-word copying.  If the source
  164.  * is not aligned, we branch off to the non-congruent loop.
  165.  *
  166.  *   stage:   op:
  167.  *         0  ld
  168.  *    :
  169.  * MEM_LAT+3  shrp
  170.  * MEM_LAT+4  st
  171.  *
  172.  * On Itanium, the pipeline itself runs without stalls.  However,  br.ctop
  173.  * seems to introduce an unavoidable bubble in the pipeline so the overall
  174.  * latency is 2 cycles/iteration.  This gives us a _copy_ throughput
  175.  * of 4 byte/cycle.  Still not bad.
  176.  */
  177. # undef N
  178. # undef Nrot
  179. # define N (MEM_LAT + 5) /* number of stages */
  180. # define Nrot ((N+1 + 2 + 7) & ~7) /* number of rotating regs */
  181. #define LOG_LOOP_SIZE 6
  182. .memcpy_long:
  183. alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame
  184. and t0=-8,src // t0 = src & ~7
  185. and t2=7,src // t2 = src & 7
  186. ;;
  187. ld8 t0=[t0] // t0 = 1st source word
  188. adds src2=7,src // src2 = (src + 7)
  189. sub t4=r0,dst // t4 = -dst
  190. ;;
  191. and src2=-8,src2 // src2 = (src + 7) & ~7
  192. shl t2=t2,3 // t2 = 8*(src & 7)
  193. shl t4=t4,3 // t4 = 8*(dst & 7)
  194. ;;
  195. ld8 t1=[src2] // t1 = 1st source word if src is 8-byte aligned, 2nd otherwise
  196. sub t3=64,t2 // t3 = 64-8*(src & 7)
  197. shr.u t0=t0,t2
  198. ;;
  199. add src_end=src,in2
  200. shl t1=t1,t3
  201. mov pr=t4,0x38 // (p5,p4,p3)=(dst & 7)
  202. ;;
  203. or t0=t0,t1
  204. mov cnt=r0
  205. adds src_end=-1,src_end
  206. ;;
  207. (p3) st1 [dst]=t0,1
  208. (p3) shr.u t0=t0,8
  209. (p3) adds cnt=1,cnt
  210. ;;
  211. (p4) st2 [dst]=t0,2
  212. (p4) shr.u t0=t0,16
  213. (p4) adds cnt=2,cnt
  214. ;;
  215. (p5) st4 [dst]=t0,4
  216. (p5) adds cnt=4,cnt
  217. and src_end=-8,src_end // src_end = last word of source buffer
  218. ;;
  219. // At this point, dst is aligned to 8 bytes and there at least 16-7=9 bytes left to copy:
  220. 1:{ add src=cnt,src // make src point to remainder of source buffer
  221. sub cnt=in2,cnt // cnt = number of bytes left to copy
  222. mov t4=ip
  223.   } ;;
  224. and src2=-8,src // align source pointer
  225. adds t4=.memcpy_loops-1b,t4
  226. mov ar.ec=N
  227. and t0=7,src // t0 = src & 7
  228. shr.u t2=cnt,3 // t2 = number of 8-byte words left to copy
  229. shl cnt=cnt,3 // move bits 0-2 to 3-5
  230. ;;
  231. .rotr val[N+1], w[2]
  232. .rotp p[N]
  233. cmp.ne p6,p0=t0,r0 // is src aligned, too?
  234. shl t0=t0,LOG_LOOP_SIZE // t0 = 8*(src & 7)
  235. adds t2=-1,t2 // br.ctop is repeat/until
  236. ;;
  237. add t4=t0,t4
  238. mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy
  239. mov ar.lc=t2
  240. ;;
  241. nop.m 0
  242. ;;
  243. nop.m 0
  244. nop.i 0
  245. ;;
  246. nop.m 0
  247. ;;
  248. (p6) ld8 val[1]=[src2],8 // prime the pump...
  249. mov b6=t4
  250. br.sptk.few b6
  251. ;;
  252. .memcpy_tail:
  253. // At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is
  254. // less than 8) and t0 contains the last few bytes of the src buffer:
  255. (p5) st4 [dst]=t0,4
  256. (p5) shr.u t0=t0,32
  257. mov ar.lc=saved_lc
  258. ;;
  259. (p4) st2 [dst]=t0,2
  260. (p4) shr.u t0=t0,16
  261. mov ar.pfs=saved_pfs
  262. ;;
  263. (p3) st1 [dst]=t0
  264. mov pr=saved_pr,-1
  265. br.ret.sptk.many rp
  266. ///////////////////////////////////////////////////////
  267. .align 64
  268. #define COPY(shift,index)
  269.  1: { .mib
  270. (p[0]) ld8 val[0]=[src2],8;
  271. (p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift;
  272. brp.loop.imp 1b, 2f
  273.     };
  274.  2: { .mfb
  275. (p[MEM_LAT+4]) st8 [dst]=w[1],8;
  276. nop.f 0;
  277. br.ctop.dptk.few 1b;
  278.     };
  279. ;;
  280. ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */
  281. ;;
  282. shrp t0=val[N-1],val[N-index],shift;
  283. br .memcpy_tail
  284. .memcpy_loops:
  285. COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */
  286. COPY(8, 0)
  287. COPY(16, 0)
  288. COPY(24, 0)
  289. COPY(32, 0)
  290. COPY(40, 0)
  291. COPY(48, 0)
  292. COPY(56, 0)
  293. END(memcpy)