memmove_32.S 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #include <linux/export.h>
  3. #include <linux/linkage.h>
  4. SYM_FUNC_START(memmove)
  5. /*
  6. * void *memmove(void *dest_in, const void *src_in, size_t n)
  7. * -mregparm=3 passes these in registers:
  8. * dest_in: %eax
  9. * src_in: %edx
  10. * n: %ecx
  11. * See also: arch/x86/entry/calling.h for description of the calling convention.
  12. *
  13. * n can remain in %ecx, but for `rep movsl`, we'll need dest in %edi and src
  14. * in %esi.
  15. */
  16. .set dest_in, %eax
  17. .set dest, %edi
  18. .set src_in, %edx
  19. .set src, %esi
  20. .set n, %ecx
  21. .set tmp0, %edx
  22. .set tmp0w, %dx
  23. .set tmp1, %ebx
  24. .set tmp1w, %bx
  25. .set tmp2, %eax
  26. .set tmp3b, %cl
  27. /*
  28. * Save all callee-saved registers, because this function is going to clobber
  29. * all of them:
  30. */
  31. pushl %ebp
  32. movl %esp, %ebp // set standard frame pointer
  33. pushl %ebx
  34. pushl %edi
  35. pushl %esi
  36. pushl %eax // save 'dest_in' parameter [eax] as the return value
  37. movl src_in, src
  38. movl dest_in, dest
  39. /* Handle more 16 bytes in loop */
  40. cmpl $0x10, n
  41. jb .Lmove_16B
  42. /* Decide forward/backward copy mode */
  43. cmpl dest, src
  44. jb .Lbackwards_header
  45. /*
  46. * movs instruction have many startup latency
  47. * so we handle small size by general register.
  48. */
  49. cmpl $680, n
  50. jb .Ltoo_small_forwards
  51. /* movs instruction is only good for aligned case. */
  52. movl src, tmp0
  53. xorl dest, tmp0
  54. andl $0xff, tmp0
  55. jz .Lforward_movs
  56. .Ltoo_small_forwards:
  57. subl $0x10, n
  58. /* We gobble 16 bytes forward in each loop. */
  59. .Lmove_16B_forwards_loop:
  60. subl $0x10, n
  61. movl 0*4(src), tmp0
  62. movl 1*4(src), tmp1
  63. movl tmp0, 0*4(dest)
  64. movl tmp1, 1*4(dest)
  65. movl 2*4(src), tmp0
  66. movl 3*4(src), tmp1
  67. movl tmp0, 2*4(dest)
  68. movl tmp1, 3*4(dest)
  69. leal 0x10(src), src
  70. leal 0x10(dest), dest
  71. jae .Lmove_16B_forwards_loop
  72. addl $0x10, n
  73. jmp .Lmove_16B
  74. /* Handle data forward by movs. */
  75. .p2align 4
  76. .Lforward_movs:
  77. movl -4(src, n), tmp0
  78. leal -4(dest, n), tmp1
  79. shrl $2, n
  80. rep movsl
  81. movl tmp0, (tmp1)
  82. jmp .Ldone
  83. /* Handle data backward by movs. */
  84. .p2align 4
  85. .Lbackwards_movs:
  86. movl (src), tmp0
  87. movl dest, tmp1
  88. leal -4(src, n), src
  89. leal -4(dest, n), dest
  90. shrl $2, n
  91. std
  92. rep movsl
  93. movl tmp0,(tmp1)
  94. cld
  95. jmp .Ldone
  96. /* Start to prepare for backward copy. */
  97. .p2align 4
  98. .Lbackwards_header:
  99. cmpl $680, n
  100. jb .Ltoo_small_backwards
  101. movl src, tmp0
  102. xorl dest, tmp0
  103. andl $0xff, tmp0
  104. jz .Lbackwards_movs
  105. /* Calculate copy position to tail. */
  106. .Ltoo_small_backwards:
  107. addl n, src
  108. addl n, dest
  109. subl $0x10, n
  110. /* We gobble 16 bytes backward in each loop. */
  111. .Lmove_16B_backwards_loop:
  112. subl $0x10, n
  113. movl -1*4(src), tmp0
  114. movl -2*4(src), tmp1
  115. movl tmp0, -1*4(dest)
  116. movl tmp1, -2*4(dest)
  117. movl -3*4(src), tmp0
  118. movl -4*4(src), tmp1
  119. movl tmp0, -3*4(dest)
  120. movl tmp1, -4*4(dest)
  121. leal -0x10(src), src
  122. leal -0x10(dest), dest
  123. jae .Lmove_16B_backwards_loop
  124. /* Calculate copy position to head. */
  125. addl $0x10, n
  126. subl n, src
  127. subl n, dest
  128. /* Move data from 8 bytes to 15 bytes. */
  129. .p2align 4
  130. .Lmove_16B:
  131. cmpl $8, n
  132. jb .Lmove_8B
  133. movl 0*4(src), tmp0
  134. movl 1*4(src), tmp1
  135. movl -2*4(src, n), tmp2
  136. movl -1*4(src, n), src
  137. movl tmp0, 0*4(dest)
  138. movl tmp1, 1*4(dest)
  139. movl tmp2, -2*4(dest, n)
  140. movl src, -1*4(dest, n)
  141. jmp .Ldone
  142. /* Move data from 4 bytes to 7 bytes. */
  143. .p2align 4
  144. .Lmove_8B:
  145. cmpl $4, n
  146. jb .Lmove_4B
  147. movl 0*4(src), tmp0
  148. movl -1*4(src, n), tmp1
  149. movl tmp0, 0*4(dest)
  150. movl tmp1, -1*4(dest, n)
  151. jmp .Ldone
  152. /* Move data from 2 bytes to 3 bytes. */
  153. .p2align 4
  154. .Lmove_4B:
  155. cmpl $2, n
  156. jb .Lmove_1B
  157. movw 0*2(src), tmp0w
  158. movw -1*2(src, n), tmp1w
  159. movw tmp0w, 0*2(dest)
  160. movw tmp1w, -1*2(dest, n)
  161. jmp .Ldone
  162. /* Move data for 1 byte. */
  163. .p2align 4
  164. .Lmove_1B:
  165. cmpl $1, n
  166. jb .Ldone
  167. movb (src), tmp3b
  168. movb tmp3b, (dest)
  169. .p2align 4
  170. .Ldone:
  171. popl dest_in // restore 'dest_in' [eax] as the return value
  172. /* Restore all callee-saved registers: */
  173. popl %esi
  174. popl %edi
  175. popl %ebx
  176. popl %ebp
  177. RET
  178. SYM_FUNC_END(memmove)
  179. EXPORT_SYMBOL(memmove)